PR Reconcile Ledger (what each pull request was resolved to)
The durable record the pull-request reconciliation pool keeps: for each open pull request a worker session worked, one row saying what it concluded — landed, already present, held for a person, or blocked — together with the session that decided it. A later rescan reads the latest row per pull request so resolved work is never redone and a request still needing a person is never closed.
What it is
The reconciliation pool is a scheduled job that finds open pull requests, hands clusters of them to worker sessions, and has each session try to bring a request's work onto local master. The ledger is where that session records what it decided for each request. It is an append-only table: every attempt adds a row, and the newest row for a request is that request's current state.
This record is the pool's only "done" signal. Without a row, a request looks unresolved, so the pool hands it to a session again on the next tick — and again. A row that names a request as needing a person is likewise read back by the closing job, so a request that was NOT landed is never quietly closed.
Where to find it
There is no screen for it. The ledger lives on the local control server (127.0.0.1:19519), with two routes:
POST /pr-reconcile-ledger/record— a worker records what it resolved ONE request to.GET /pr-reconcile-ledger/latest?ghSlug=— the latest resolution per request for a repository, which a rescan reads.
It is a table, pr_reconcile_ledger, in the local database. These routes are bearer-authenticated and are deliberately separate from the opt-in PR Merge Queue panel — they are not gated by that panel's setting and never answer "disabled".
How it behaves
A worker posts one row per request: prNumber, a resolution, and optionally a short reason, the branch it used, the head commit, and a repository slug. The session that wrote it is taken from the caller's X-AMC-Source-Session-Id header, never from the body, so the record of who resolved a request cannot be forged. The repository defaults to the reconciliation repo; pass a slug to target another one.
The resolution must be one of a fixed set. A value outside the set is refused:
- already-merged — the request's work is already on the base branch.
- reconciled-clean / reconciled-complete — landed cleanly with nothing omitted.
- reconciled-partial — landed, but some of the request's work was left out, so it stays open.
- reconciled-with-changes — an older, ambiguous value still accepted for rows already stored; never write it again, and never read it as safe to close.
- landed-locally — on local master, waiting to reach the remote.
- needs-human — a person has to decide.
- dependency-hold — waiting on another change to land first.
- blocked — a genuine blocker, or the request is broken.
- blocked-environment — this machine could not prepare it (a degraded drive, a stale build, a missing tool). This is never the request's fault: its attempts are discounted, and it is picked up again once the machine recovers, so a bad box can never park a request as owing a person.
Two behaviours are worth knowing. First, recording a terminal not-landed decision (needs-human, dependency-hold, blocked or blocked-environment) also takes the ready tag off the reconciliation branch that carries that request, so the lander stops being offered work the pool already rejected. Second, the same outcome is written twice — once privately here, and once publicly as a verdict on the request — from ONE outcome, so the private record and the public verdict can never disagree.
Rows are purged after 30 days, so treat this as recent-run telemetry rather than a permanent archive.
For agents
- Routes:
src/main/services/cli/cli-server-pr-reconcile-ledger-routes.ts. Storage:src/main/db/queries-pr-reconcile-ledger.ts. - The resolution vocabulary and the resolution→verdict map live in
src/shared/pr-reconcile-resolution.ts— the single source of truth for both. - The pool is
scripts/pr-reconcile-cron.mjs(I/O) overscripts/lib/pr-reconcile-cron.mjs(policy); the worker readsscripts/pr-reconcile-prompt.txt. - The ready-tag withdrawal on a not-landed decision is
src/main/services/auto-lander/reconcile-rejection-veto.ts. - Default repository slug is
jlstradingco/Agent-Orchestrator; passghSlugto target another.
Related
- pr-merge-queue.md — the in-app queue that lists and triages open pull requests
- pr-janitor.md — the nightly job that reads this ledger to decide what is safe to close
- auto-lander-dashboard.md — where a tagged reconciliation branch is landed
- cron-jobs.md — the schedule the reconciliation pool runs on, and the retention sweep
Last verified 2026-10-06