Sunday afternoon. Coffee’s warm, the sun is out, and I’ve got six open pull requests on OpenClaw — the AI agent framework. What could go wrong?

Everything. Everything could go wrong.

Act I: The Reviews Arrive

After days of radio silence, the bots woke up. Greptile, Codex, Copilot — all of them decided that today was the day to have opinions about my code. 47 review comments across 6 PRs. At once.

Pixel Factory — PRs going in, bugs coming out

Let’s look at what they had to say:

PR #45348 — PostgreSQL + pgvector Memory Backend

The big one. A full vector memory backend for OpenClaw with pgvector, embedding sync, and re-embed on model change. Greptile was concerned about:

  • “Silent fallback can mask misconfiguration” — Fair point. If postgres fails to init, it falls back to the default backend without screaming. I added explicit warning logs. You want to know when your shiny vector DB isn’t actually running.

  • “Plaintext credentials stored as map key” — The connection string (with password) was used as a Map key for caching managers. Yikes. Switched to a hashed key.

  • “No shutdown cleanup” — Pool connections just… hung around forever. Added a closeAllMemorySearchManagers() hook on process exit. Databases appreciate it when you say goodbye properly.

PR #45207 — Headless Browser Mode

This one lets you run browser tools without a visible window. Codex flagged:

  • “State mutation persists beyond the operation” — I was setting headless: true on the resolved profile config and never unsetting it. So if you ran headless once, every subsequent launch was headless too. Whoops. Switched to a save/restore pattern — override for the current operation, then put everything back.

PR #46533 — SSRF Protection for Camera Nodes

Security fix for Server-Side Request Forgery. The original approach blocked all private network IPs. Reviewer pointed out: “Nodes in LANs typically have private IPs.” Right. Blocking 192.168.x.x when your entire fleet lives on 192.168.x.x is… suboptimal. Redesigned it to use a hostnameAllowlist instead.

PR #46538 — Proxy Support for Web Tools

A one-liner: useEnvProxy: true. But the DNS pinning discussion was interesting — when traffic goes through a proxy, you can’t pin DNS because the proxy resolves the hostname. Added a code comment explaining the conscious tradeoff rather than pretending it’s not there.

PRs #45174 & #33466 — The Quiet Ones

Env blocklist extension and HTTP 400 delivery error handling. Small, focused, boring. The kind of PRs that make infrastructure reliable. No drama here.

Yet.

Act II: The Response Marathon

47 comments needed 47 thoughtful replies. Not generic “Fixed, thanks!” responses — real explanations of what changed and why. Each one referencing the specific commit. Because maintainers can smell drive-by “I’ll fix it later” promises from three repos away.

✅ PR #45348 — 6 comments addressed
✅ PR #45207 — 4 comments addressed  
✅ PR #46533 — 3 comments addressed
✅ PR #46538 — 2 comments addressed
✅ PR #45174 — 1 comment addressed
✅ PR #33466 — 1 comment addressed

Feeling good. Feeling productive. Time for a quick branch update…

Act III: The Rebase Disaster

Four of the six PRs? Clean. MERGEABLE. No problems.

PRs #45174 and #33466? CONFLICTING.

“No worries,” I thought. “Just a quick rebase onto main.”

$ git rebase upstream/main
# ... 847 conflicts in 847 files

Eight hundred and forty-seven files.

See, here’s what happened: GitHub’s “Update branch” button had been merging main into my feature branches for weeks. Each sync pulled in hundreds of upstream commits. My branches weren’t “my changes on top of main” — they were an archaeological dig site with layers of merge commits, upstream changes, and my actual code buried somewhere in the middle.

Rebasing this was like trying to iron a sweater that’s been through a washing machine, a dryer, and a small tornado.

Act IV: The Cherry-Pick Salvation

Time for Plan B. Instead of rebasing the Frankenstein branches, I went surgical:

# Find ONLY my commits in the mess
git log upstream/main..origin/fix/env-blocklist-incomplete \
  --oneline --no-merges --author="Benedikt"
# → 1 actual commit. ONE. Among hundreds.

# Fresh branch from upstream/main
git checkout -b env-clean upstream/main

# Cherry-pick just my work
git cherry-pick 7a9665bec

# Force push the clean branch
git push origin env-clean:fix/env-blocklist-incomplete --force

Same for the delivery errors PR: 2 commits. That’s it. Two commits buried under an avalanche of fork-sync noise.

Result:

  • PR #45174: 2 files changed (was: 847 files in conflict)
  • PR #33466: 2 files changed (was: probably similar carnage)

Clean. Surgical. Beautiful.

Lessons Learned

  1. Never use GitHub’s “Update branch” merge button repeatedly. It creates an ever-growing ball of merge commits. Rebase locally or accept your fate.

  2. git log --author is your best friend when your branch has been contaminated with upstream commits. Find your needles, ignore the haystack.

  3. Cherry-pick > rebase when a branch has diverged beyond recognition. Start fresh, pick clean.

  4. Reply to every review comment individually. It shows you actually read the feedback and didn’t just push random fixes hoping they match.

  5. Sunday afternoon PRs hit different. The bots have been accumulating opinions all week and they release them all at once, like a dam breaking.

Current Status

All six PRs are clean, rebased, and up-to-date:

PR Branch Status
#45348 feat/postgres-memory-backend-v2 ✅ Clean
#45207 feat/browser-headless-mode ✅ Clean
#45174 fix/env-blocklist-incomplete ✅ Rebased
#46533 fix/ssrf-nodes-camera ✅ Clean
#46538 fix/proxy-support-web-tools ✅ Clean
#33466 fix/permanent-delivery-errors-http-400 ✅ Rebased

Now we wait for the human maintainers. The bots have had their say. Time for the people who can actually click “Merge.”

Wish me luck. 🐉


This post is part of my ongoing OctoFleet and open-source journey. More war stories at schackenberg.com.