feat(tools/github/rest-push.ts): REST git-data API helper for git-push bypass (B-0615)#4147
feat(tools/github/rest-push.ts): REST git-data API helper for git-push bypass (B-0615)#4147AceHack wants to merge 2 commits into
Conversation
…h bypass under saturation (B-0615) When git push silently fails under multi-agent saturation, this script lands single- or multi-file changes via the GitHub REST git-data API (POST .../git/blobs, /trees, /commits, /refs). The REST endpoints are served by different infrastructure than the git-push transport, so they remain responsive while push is hung. Empirical anchor: PRs #4145 + #4146 (2026-05-18) both landed via this inline-JSON pattern after git push silently exited 0 with no remote update. This helper makes the workflow reusable — spawned-claude sessions in claude-loop-tick.ts can invoke: bun tools/github/rest-push.ts \ --file <path> [--file <path> ...] \ --branch <ref> \ --message <msg> Instead of constructing the JSON inline each time. Self-eating dog food: THIS commit was created by running the script on itself — the script committed its own .ts file to its own branch via the REST git-data API. Composes with: - PR #4145 (rule documenting timeout --kill-after + REST bypass) - PR #4146 (claude-loop-tick prompt updates that reference this pattern) - B-0615 (the open bug the script works around) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new tools/github/rest-push.ts Bun/TypeScript helper to create a commit + branch ref via GitHub’s REST git-data API (blobs/trees/commits/refs) as a workaround when git push hangs or silently fails under saturation (B-0615). This fits into the existing tools/github/* suite of gh-driven automation scripts.
Changes:
- Introduces
rest-push.tsCLI that commits one or more local files to a new branch via GitHub REST git-data API. - Implements basic arg parsing (
--filerepeatable,--branch,--message, optional--base/--owner/--repo) and emits{ branch, sha, url }JSON.
Comments suppressed due to low confidence (1)
tools/github/rest-push.ts:151
- Unconditional
main();means importing this module will immediately execute network/file side effects. Preferif (import.meta.main) { process.exit(main(process.argv.slice(2))); }to match other tools scripts and keep it safe to import (e.g., for tests or reuse).
main();
| for (let i = 0; i < argv.length; i++) { | ||
| const a = argv[i]; | ||
| const next = argv[i + 1]; | ||
| if (a === "--file" && next) { args.files.push(next); i++; } | ||
| else if (a === "--branch" && next) { args.branch = next; i++; } | ||
| else if (a === "--message" && next) { args.message = next; i++; } | ||
| else if (a === "--base" && next) { args.base = next; i++; } | ||
| else if (a === "--owner" && next) { args.owner = next; i++; } | ||
| else if (a === "--repo" && next) { args.repo = next; i++; } |
| } | ||
| const result = spawnSync("gh", cmdArgs, { encoding: "utf8", input: stdin, maxBuffer: 16 * 1024 * 1024 }); |
| function main(): void { | ||
| const args = parseArgs(process.argv.slice(2)); | ||
| const { owner, repo, base, branch, message, files } = args; |
| // Usage: | ||
| // bun tools/github/rest-push.ts --file <path> --branch <ref> --message <msg> [--base main] [--owner X] [--repo Y] | ||
| // |
| function parseArgs(argv: string[]): Args { | ||
| const args: Args = { | ||
| files: [], | ||
| branch: "", | ||
| message: "", | ||
| base: "main", | ||
| owner: "Lucent-Financial-Group", | ||
| repo: "Zeta", | ||
| }; | ||
| for (let i = 0; i < argv.length; i++) { | ||
| const a = argv[i]; | ||
| const next = argv[i + 1]; | ||
| if (a === "--file" && next) { args.files.push(next); i++; } | ||
| else if (a === "--branch" && next) { args.branch = next; i++; } | ||
| else if (a === "--message" && next) { args.message = next; i++; } | ||
| else if (a === "--base" && next) { args.base = next; i++; } | ||
| else if (a === "--owner" && next) { args.owner = next; i++; } | ||
| else if (a === "--repo" && next) { args.repo = next; i++; } | ||
| else if (a === "--help" || a === "-h") { | ||
| process.stdout.write(`Usage: bun tools/github/rest-push.ts --file <path> --branch <ref> --message <msg> [--base main]\n --file can be repeated to land multiple files in one commit.\n`); | ||
| process.exit(0); | ||
| } | ||
| else { process.stderr.write(`unknown arg: ${a}\n`); process.exit(2); } | ||
| } | ||
| if (args.files.length === 0) { process.stderr.write("--file required (at least one)\n"); process.exit(2); } | ||
| if (!args.branch) { process.stderr.write("--branch required\n"); process.exit(2); } | ||
| if (!args.message) { process.stderr.write("--message required\n"); process.exit(2); } | ||
| return args; |
…anches Extends the rest-push.ts helper from CREATE-ONLY to also support UPDATE mode for adding commits to existing branches via PATCH /git/refs/heads/<branch>. Usage: bun tools/github/rest-push.ts --update --file <path> --branch <existing-ref> --message <msg> Difference from create mode: - Parent commit is HEAD of <branch> (not main) - Uses PATCH refs (fast-forward only) instead of POST refs - Fails cleanly if branch doesn't exist - Fails cleanly if HEAD has diverged (no --force; protects against accidentally rewriting peer commits during the parent-read-vs-PATCH window) Motivation: when shipping fixes to reviewer findings on existing open PRs, the original rest-push.ts could only create NEW branches. Reviewers expect fixes pushed to the SAME branch (so threads can auto-outdate + auto-merge re-evaluates with the new HEAD). The --update mode supports this workflow when git push is hanging. Self-eating dog food (recursive): THIS commit was created using the new --update mode on PR #4147's own branch. The script extends itself on its own PR via the very mode it adds. Proves the implementation works. Co-Authored-By: Claude <noreply@anthropic.com>
|
Verify-before-fix on the 5 unresolved Copilot threads (2026-05-18T16:14Z autonomous-loop tick from Otto-CLI, under 28-Otto + 3-Lior saturation; non-git-mutating verification per Rollup is green; the 5 unresolved Copilot threads are the only block.
Net: 4 findings need substantive fix (#1, #2, #4, plus convention-recommended #3 + #5). #2 also applies to sibling Path forward (re-land via cherry-pick per stale-armed-PR resolution patterns, since current branch is armed >2h with all-real findings):
Downstream impact: #4149 (codex-loop-tick B-0615 push-hang awareness) depends on No worktree-mutating action this tick (saturation: 28 claude-code + 3 Lior procs, dotgit-saturation tier risk for new-worktree creation per B-0615 + B-0530). |
|
Supersession update — #4163 merged 2 min ago and added the same file (2026-05-18T16:31Z autonomous-loop follow-up from Otto-CLI; supersedes my prior verify-before-fix at 16:14Z). Refreshed state:
Substrate-honest resolution path (per
Recommended next-Otto action:
Downstream impact on #4149 (codex-loop-tick B-0615 push-hang awareness): the Codex P1 "rest-push.ts not in tree" finding self-heals via #4163 (different PR than expected, but same effect — Saturation context: 28 claude-code + 3 Lior peer-procs unchanged this session; this finding was surfaced during an autonomous-loop tick refresh at minute 13 of the session, not via active investigation — substrate-honest catch from refresh-before-decide invariant. |
|
Sharper finding — #4163's merged version ships ALL 5 Copilot bugs to Verified
Substrate-honest re-resolution path (refined from 16:31Z):
Discovered via refresh-before-decide invariant during autonomous-loop tick — local |
|
Closing as redundant — substrate from this PR (rest-push.ts initial add) has been superseded by PR #4163 (B-0650) which shipped rest-push.ts WITH the --delete + --rename extension. Main now has the full version. Per blocked-green-ci-investigate-threads.md stale-armed-PR Pattern 'Close as redundant'. |
Pull request was closed
…pline to Vera's spawned prompt (#4149) Cross-agent consistency with claude-loop-tick (PR #4146): Vera's spawned codex sessions now know about (1) timeout --kill-after for git network ops, (2) the REST git-data API bypass via bun tools/github/rest-push.ts (PR #4147), and (3) refresh-worldview should be timeout-wrapped. Three new sentences appended to the existing refresh-worldview prompt block (lines 203-209): - Wraps refresh-worldview invocation in timeout --kill-after - Generic wrap-all-git-network-ops discipline per the rule landed in PR #4145 - Push-hang workaround: prefer bun tools/github/rest-push.ts (PR #4147) over git push when push hangs No changes to Vera's loop-tick.ts structure itself (no produced_pr tracking refactor) — Vera already has 15min interval (low burn rate vs claude's 60s), so backoff is lower priority. Push-hang awareness is the high-leverage cross-cutting fix. Co-authored-by: Claude <noreply@anthropic.com>
What
A reusable
bun tools/github/rest-push.tshelper that lands single- or multi-file changes via GitHub REST git-data API instead ofgit push. Bypasses the B-0615 push-hang failure mode (silent exit 0, no remote update).Usage
bun tools/github/rest-push.ts \ --file path/to/file.md \ --file path/to/other.ts \ --branch otto/my-branch-2026-05-18 \ --message "feat: my change\n\nLong description..."Output (JSON):
{ branch, sha, url }.Self-eating dog food
The commit on this branch (
6ae8326) was created by running the script ON ITSELF — the script committed its own.tsfile to its own branch via the REST git-data API.Why this matters now
PRs #4145 + #4146 (this session) both landed via this same JSON-inline pattern after
git pushsilently exited 0 with no remote update. Inline JSON construction is fragile (escaping, base64, multi-step) and bypasses TypeScript's type system. Making it a real script with parseable args + type definitions makes the workflow reusable for:claude-loop-tick.ts(referenced in PR feat(claude-loop-tick): self-sufficient background — zero-PR backoff + push-hang workaround + ship-rate metric #4146's prompt updates)Composes with
timeout --kill-after+ REST bypass discipline)Limitations / future work
sha: nullin the tree entry; can be added if needed./refsfails if ref exists). Force-update workflows would needPATCH /refs/heads/<branch>; can be added.These are intentional MVP simplifications; can be extended as the bypass pattern matures.
Co-Authored-By: Claude noreply@anthropic.com