On this page
On this page
Project and contributing
PR GitHub transport
PR GitHub transport
These contracts are owned by scripts/pr; they do not authorize a public write or bypass a required gate.
GitHub observations and publication
OPENCLAW_PR_GIT selects the Git executable. Startup checks that binary with a
10-second deadline before choosing wrapper code; Darwin process-identity Python
calls use the same deadline. PR metadata, repository authority, writer identity,
comments, contributor authors, and author permissions prefer REST, with GraphQL
fallback on confirmed primary core quota exhaustion. Review snapshots omit unused
check rollups, and preparation reads only the live head fields it consumes.
Repository discovery uses the CLI's local default and host resolution, without a
quota-dependent HEAD request. Host-qualified locators go directly to the API;
review metadata reuses the resolved URL.
Each PR-head observation and merge snapshot explicitly requests
Cache-Control: max-age=0: the relay revalidates that read and may publish its
result, while separate before/after observations must never reuse one cached fact.
The landing-snapshot GraphQL query must exactly match the shipped Octopool shim's allowlist; branch identity comes from the existing REST source-acquisition and cleanup reads.
Writer identity uses the protected CLI with included headers on both transports
to retain the native writer route. Reviewer assignment requires REST and verifies
the retained assignee. The CI watcher polls GraphQL summaries, expanding details
for failures or pending checks after CI succeeds; primary quota exhaustion selects
REST with complete check/status and workflow evidence. In --completion ci-run
mode, active polling revalidates the attached run and attempt-specific job pages
with REST ETags. Only a successful 304 Not Modified reuses the previous body;
changed responses and new attempts replace that evidence. Missing ETags retain
ordinary fresh reads. Validators live only for this watcher and credential/host
scope. PR head, lifecycle, and conflict observations remain fresh each poll, and
completed runs do not reload job progress. gh api --include uses the protected
CLI’s native caller-authenticated route, not the pooled relay; authenticated
304s avoid GitHub’s primary quota but still make network requests and remain
subject to secondary limits.
Successful authentication is reused within one shell operation and its nested
worktree entries; new processes and changed credential selection require a new
probe. This private process state is never inherited or written to artifacts.
merge_verify takes one options record with replacementHead,
autoMergeRequested, and observation; a null observation requests a fresh read.
Repository identity comes from the same PR observation as its head facts. Callers
carry that observation through source acquisition and hosted gates; acquisition
still independently rereads complete source identity after the immutable fetch.
Publication revalidates immediately before each Git/GraphQL write, after transport
preparation, and compares the successful publication observation before acquisition.
PR-branch publication defaults to OPENCLAW_PR_PUSH_MODE=auto. Signed ranges
use Git; unsigned linear ranges use GitHub’s verified createCommitOnBranch
route when head-repository metadata is available. A range containing a merge
uses Git to preserve its parents and must pass the existing signature checks
or have the explicit OPENCLAW_ALLOW_UNSIGNED_GIT_PUSH=1 override. Signature
checks cover first-parent commits, or all non-baseline task commits when an
authenticated publication baseline is present. The override does not
change the unsigned-linear default. Explicit graphql mode still refuses merge
ancestry. A Git permission failure can fall back to GraphQL only for a linear
range; a merge preserves the original Git failure instead. Uncertain outcomes
never authorize another publication.
The explicit pending-proof publication purpose always requires the original signed Git commit. It rejects unsigned overrides and GraphQL commit aliases, including permission-error fallback. Its canonical landing observation must show no auto-merge request or queue membership before publication; missing facts refuse. This purpose produces publication evidence only, leaving the correction review and ordinary landing gates unresolved.
Ordinary immediate squash prefers REST. Explicit recovery of a validated retained intent starts with GraphQL; normal fallback and immediate-only recovery gates still apply. Admission reads switch transports only for confirmed primary quota exhaustion or unsupported REST policy or mergeability projections, including UNKNOWN; secondary throttles and access failures never authorize a switch. REST requires absence of merge queues, supported applicable rules, exact-head publisher-bound checks, and the retained-outcome lifecycle. Classic-protection discovery is not required; GitHub enforces it at the pinned merge request. It preserves configured message content from pinned published commits or the PR body and leaves the title to GitHub. Choose the transport before dispatch; never replay an uncertain mutation through another API. Completion comments use the receipt observation's transport and keep their one-attempt marker. Auto-merge, queues, admin admission, and non-squash merges require GraphQL; GitHub has no REST auto-merge endpoint. Legacy hosted workflow proof requires REST. Fallback never waives a required gate. API failures preserve safe quota and retry metadata from the original response. When that response has no usable HTTP framing, a separate GraphQL/core quota probe is labeled supplemental and does not establish the failed request's reset. Diagnostics never add automatic retries.
Octopool string rewrite protection
Keep gh on the Octopool shim; never disable string rewrite protection or select
the raw GitHub CLI to get a landing through. review-init resolves the repository
with the local gh browse command and a child-only URL-printing launcher. Older
Octopool versions reject this singleton command before their guarded best-effort
path. Upgrade to Octopool 0.7.1 or later; setting an explicit
host-qualified GH_REPO=github.com/openclaw/openclaw also avoids discovery while
preserving the subsequent authoritative API checks.
Ordinary immediate REST squash uses gh api --method PUT repos/OWNER/REPO/pulls/NUMBER/merge-async --input <absolute-file> with JSON containing the full prepared 40-hex sha,
merge_method: "squash", merge_action: "direct_merge", bypass_rules: false, and
the inspected commit_message. It refuses stacked PRs because this workflow
reviews one PR. The outcome retains the returned UUID before polling; subsequent
merge-run calls read that UUID once and reconcile the authoritative PR/tree.
Acceptance and enqueued are not merge completion. Failed, expired, conflicting,
or lost responses never authorize automatic resubmission or another transport.
Existing auto/queue/admin and GraphQL-quota routes keep their own contracts; the
explicit prior-CI admin route still uses the synchronous /merge endpoint.
Async PUT and status GET prepend -H 'X-Octopool-Require: merge-async-v1' as the first
API option, before --hostname. This requires the structural async merge guard in
Octopool PR #231: older protected wrappers reject the marker before rewriting or native
GitHub I/O. Upgrade Octopool if refused; never remove the marker or replay an
uncertain intent. Native gh and empty rewrite policies pass the harmless header
through without rewriting authority. No Worker deployment or credential change
is required. Checking a response after dispatch cannot replace this guard.
The shared GitHub subprocess owner stages internal
--input - payload bytes in a private temporary file, keeps child stdin empty,
and removes the file after synchronous completion. Keep the explicit SHA even
when newer Octopool can resolve a missing one. Auto-merge needs Octopool's protected auto-merge support
(openclaw/octopool#179), a numeric PR, --squash --auto --match-head-commit SHA,
an explicit --subject, and --body-file. The wrapper supplies GitHub's
current-head viewerMergeHeadlineText preview so repository title defaults stay
intact. Octopool 0.6.10 and 641ce3c do not support that auto shape.
Prepare's reviewer assignment uses the exact issue-assignee POST with raw
assignees[] fields. Fork commit publication declares its GraphQL JSON with
--input, so the guard can inspect it; Octopool's aggregate input bound still
applies. Native CLI admin, non-squash, queue, and auto-cancellation variants are not
covered by the accepted shapes above. Do not replace them with an immediate REST
merge, which changes admission semantics. A blocked dispatch still follows the
retained-outcome recovery rules; the generic guard error is not authority
to clear or retry an intent.