Skip to content

Follow the update job, and diff from what actually published - #553

Open
galshubeli wants to merge 1 commit into
ci/harden-update-graph-payloadfrom
ci/poll-update-graph-job
Open

Follow the update job, and diff from what actually published#553
galshubeli wants to merge 1 commit into
ci/harden-update-graph-payloadfrom
ci/poll-update-graph-job

Conversation

@galshubeli

Copy link
Copy Markdown
Contributor

Why

Stacked on #552 — review that one first; this PR's diff against it is one workflow file, one function, and five tests.

Two problems left over from the pipeline review, both needing FalkorDB/GraphRAG-Server#357 deployed before this can merge.

A failed run's files are lost forever. The workflow diffs from github.event.before, which is "what main used to be" — it says nothing about whether the run for that commit succeeded. When one fails, the next push diffs from the failed run's head and everything in between is never sent again. That is why #545's one-file change is missing from the live graph with nothing to re-send it.

A large run cannot report its own outcome. A 190-file diff took 2h23m against a 300s connection ceiling. CI went red at five minutes; the work published at 13:33 with nobody watching.

What changed

Diff from what actually published. The workflow asks GET /api/admin/update-graph/state for last_ingested_sha — written by the compare-and-set that publishes, so it means "the commit whose content is live", not "the last commit CI mentioned". Diffing from it picks up everything since the last run that landed, including the work of runs that didn't.

Fallbacks, in order: the published sha → the push event's parent → refuse. _resolve_base handles a graph that has never published (no sha yet) and a sha rewritten out of history. If neither is usable it fails, because the remaining option is the empty tree, and that would re-send the entire repo as additions.

Follow the job. ?wait=false answers 202 with a job id; the workflow polls every 30s and prints each phase as it changes (copying, ingesting, reconciling, smoke, promoting, flipping).

Response What the workflow does
202 + attached: false follows the new job
202 + attached: true this commit was already in flight — follows that job rather than starting a second ingest
409 another run holds the graph's lease. Fails with an explanation instead of retrying: its result changes what this diff should have been computed against
no terminal state in 55 min fails, saying explicitly that this is not a failure — the run continues and publishes atomically. Job timeout raised to 60 min

The summary says which of the three it was. A red run now names the commit it diffed from, the job it followed, and whether it was refused, failed, or still going. Previously every one of those looked the same.

Testing

5 new tests for base resolution — published sha preferred, unreachable one falls back, empty one falls back, neither is refused, all-zero still means the empty tree. 20 in the file, run by the check-payload job from #552.

The workflow shell itself is not unit-testable here; it is deliberately boring — set -euo pipefail, explicit status checks, jq -r with defaults, and no --retry anywhere.

Merge order

  1. FalkorDB/GraphRAG-Server#357 deployed (adds /state and ?wait=false)
  2. Stop the graph-update payload dropping documents it cannot see #552
  3. this

Merging this before step 1 breaks the workflow: /state would 404 and the POST would answer 200 instead of 202.

Two halves of the same problem, both needing GraphRAG-Server#357 deployed.

**Diff from what published, not from the push event.** `github.event.before`
is "what main used to be"; it says nothing about whether the run for that
commit succeeded. When one fails, the next push diffs from the failed run's
head and the files in between are never sent again — which is why #545's
one-file change is missing from the live graph with nothing to re-send it.
The workflow now asks `GET /api/admin/update-graph/state` for
`last_ingested_sha` and diffs from that, falling back to `event.before` when
the graph has never published or the commit was rewritten away. If neither
is usable the payload builder refuses rather than diffing from the empty
tree, which would re-send the whole repo as additions.

**Follow the job instead of holding a connection.** The endpoint is called
with `?wait=false`, which answers 202 with a job id, and the workflow polls
it every 30s, printing each phase as it changes. A 190-file diff took 2h23m
against a 300s connection ceiling, so the old shape could not report the
outcome of a large run at all: it went red while the work published two
hours later.

- 409 (another run holds the graph's lease) fails the job with an
  explanation rather than retrying — its result changes what this diff
  should have been computed against
- an `attached: true` response means this commit was already in flight, so
  the workflow follows that job instead of starting a second ingest
- 55 minutes without a terminal state fails, saying explicitly that this is
  *not* a failure: the run continues and publishes atomically. Job timeout
  raised to 60 minutes to match

The step summary now names the commit it diffed from and the job it
followed, so a red run says which of the three it was: refused, failed, or
still going.

5 tests for the base resolution (published sha preferred, unreachable one
falls back, empty one falls back, neither is refused, all-zero still means
the empty tree). 20 tests total in the file.
Copilot AI lite review requested due to automatic review settings August 18, 2026 11:59
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bcad2f62-0669-4c99-acc7-3c2c9bb8ce26

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the docs-to-GraphRAG ingestion pipeline to diff against what’s actually published (server-reported last_ingested_sha) and to treat the ingestion as an asynchronous job that the workflow follows to completion, improving correctness after failed runs and observability for long ingests.

Changes:

  • Update update-graph.yml to query the server for the last published SHA, start ingestion with ?wait=false, then poll the returned job until completion/failure/timeout.
  • Add _resolve_base() in build_diff_payload.py to select a safe diff base (published → push parent → refuse) and adjust base handling in main().
  • Add 5 tests covering base selection scenarios.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
.github/workflows/update-graph.yml Switches to “diff from published SHA” and job-following semantics with longer timeout and richer step summary.
.github/scripts/build_diff_payload.py Introduces base resolution logic to safely choose a diff base (or refuse) instead of relying solely on github.event.before.
.github/scripts/test_build_diff_payload.py Adds unit tests for base resolution behavior and related edge cases.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 42 to +45
env:
GRAPH_ID: docs_benchmark
GRAPHRAG_UI_URL: ${{ vars.GRAPHRAG_UI_URL }}
UPDATE_GRAPH_TOKEN: ${{ secrets.UPDATE_GRAPH_TOKEN }}
Comment on lines +115 to +122
job=$(jq -r '.job_id' start.json)
attached=$(jq -r '.attached' start.json)
echo "job=$job" >> "$GITHUB_OUTPUT"
if [ "$attached" = "true" ]; then
echo "::notice::Attached to in-flight job $job for this same commit"
else
echo "::notice::Started job $job"
fi
echo "| | |"
echo "|---|---|"
echo "| Commit | \`${GITHUB_SHA}\` |"
echo "| Diffed from | \`${{ steps.state.outputs.published }}\` |"
Comment on lines +268 to +273
base = _git(repo, "rev-parse", "HEAD")
(repo / "guides" / "new.mdx").write_text("new\n", encoding="utf-8")
head = _commit(repo, "add a page")
monkeypatch.chdir(repo)

assert bdp._resolve_base(base, head) == base
Comment on lines 222 to +226
head = os.environ["HEAD_SHA"]

if set(base) == {"0"}:
# First push to a brand-new branch: everything in the tree is new.
base = EMPTY_TREE_SHA
elif not _commit_exists(base):
base = _resolve_base(
os.environ.get("BASE_SHA", ""), os.environ.get("BASE_SHA_FALLBACK", ""),
)
if base is None:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants