openclaw/docs/reference/scripts/github-transport.md
Vincent Koc e088b3a863
feat(pr): publish signed candidates for pending package proof (#187764)
* fix(pr): publish exact candidates for pending proof

* test(pr): frame native GitHub writer responses

* test(pr): verify pending-proof interruption custody

* fix(pr): validate proof publication reconciliation signatures

* fix(pr): bind reconciled proof receipts to current review

* fix(pr): satisfy proof publication lint rules

* test(pr): assert normalized successor interruption errors

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-10-30 01:27:19 +08:00

133 lines
9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
summary: "GitHub observations, publication, and protected Octopool dispatch for scripts/pr"
read_when:
- Changing GitHub observation, publication, or protected PR merge transport
title: "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](/reference/scripts/prior-ci) 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](https://github.com/openclaw/octopool/pull/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](/reference/scripts/merge-recovery); the generic guard error is not authority
to clear or retry an intent.