Skip to content

OpenClaw 2026.7.1-2 pin, watchdog lifecycle hardening, 99.6% test coverage - #109

Closed
garrytan wants to merge 18 commits into
chrysb:mainfrom
garrytan:main
Closed

OpenClaw 2026.7.1-2 pin, watchdog lifecycle hardening, 99.6% test coverage#109
garrytan wants to merge 18 commits into
chrysb:mainfrom
garrytan:main

Conversation

@garrytan

Copy link
Copy Markdown

Supersedes #92 (closed unmerged — much of its openclaw-migration content has since landed upstream independently; this PR carries the remaining unique work, rebased onto current main via merges with no conflicts outstanding).

What's in here

1. openclaw pin: 2026.7.1-2 (not plain 2026.7.1)

The plain 2026.7.1 npm publish has the doctor --fix bug that silently strips official external-catalog plugin ids (like codex) from plugins.allow (openclaw#107226, fixed in the 2026.7.1-2 hotfix republish, PR openclaw#108336). Since AlphaClaw's watchdog runs doctor --fix --yes during auto-repair, pinning plain 7.1 makes auto-repair actively harmful for Codex deployments. I tarball-diffed 2026.7.1 vs 2026.7.1-2 before adopting it (the hotfix was published outside openclaw's release pipeline): same dependencies, same bin/main, no new install scripts — clean.

2. Watchdog hardening for the OpenClaw 2026.7.1 gateway lifecycle

Complements the EX_CONFIG handling already on main with the other half of openclaw's new crash-loop breaker contract:

  • Safe-mode detection: after each healthy /health check, probe /readyz — when openclaw's own breaker suppresses channel autostart (gateway healthy, channels silently down), the watchdog now surfaces safeMode + suppressedChannels in status, notifies once per suppression set, and clears with a recovery notice.
  • POST /api/watchdog/resume-channels: issues openclaw's documented channels.start manual override per suppressed channel, then re-checks health. 409 when nothing is suppressed.
  • Safe-mode state resets on gateway exit/restart/stop so stale status never lingers.

3. Git-based deployment support (carried from #92)

lib/server/self-dependency.js + prepare-script wiring so AlphaClaw can be deployed from a git checkout rather than only the npm package, and unconditional usage-tracker stale-path pruning.

4. Test coverage: 71% → 99.63% lines (2,079 tests / 146 files)

Test-files-only (zero source changes): full coverage of the chat-ws WebSocket bridge (driven by a real ws server playing the gateway side of protocol v4), gateway process supervision, every route surface, the sqlite db layers, gmail/google integration, cron, cost/version services, CLI helpers, and the frontend lib/components (preact component logic exercised via a hooks harness, no DOM). The 53 remaining uncovered lines are individually documented dead code or v8-to-istanbul artifacts. Also sets vitest testTimeout: 30000 — openclaw's plugin-sdk pays a >5s first-import cost per worker, which flaked timing-sensitive suites under parallel load.

Test plan

  • Full suite green on Node 24.18.0 across four consecutive runs: 2,079 passed / 0 failed.
  • Watchdog safe-mode + EX_CONFIG flows covered by unit tests plus an e2e suite driving the real watchdog through the real Express routes against a stateful fake gateway.
  • /readyz payload shape and channels.start RPC verified against the actual openclaw 2026.7.1-2 dist, not just release notes.

🤖 Generated with Claude Code

garrytan and others added 16 commits June 11, 2026 18:36
Latest npm stable; Fable 5 support lands in the 2026.6.6 train once its publish is fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
npm only runs prepack for registry publishes, not when installing
from a git URL — so consumers pinning github:garrytan/alphaclaw got
no lib/public/dist/ or generated Tailwind CSS (both gitignored),
leaving the setup UI blank. prepare runs for git deps and rebuilds
the same artifacts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add prepare script so git-dependency installs build the UI
ensureUsageTrackerPluginEntry only ever *added* the canonical
__dirname-resolved usage-tracker path; it never removed paths left by a
previous install at a different location. After a deployment switches
from the @chrysb/alphaclaw npm package (installed at
/app/node_modules/@chrysb/alphaclaw/...) to a git dependency (installed
at /app/node_modules/alphaclaw/...), the old path lingers in
openclaw.json, no longer exists on disk, and OpenClaw rejects the whole
config as invalid — breaking the gateway and every openclaw subcommand
(status/health/logs/doctor).

Prune any `.../plugin/usage-tracker` load path that isn't the canonical
one in the boot reconcile (ensureUsageTrackerPluginConfig), so existing
configs migrate on the next boot. Kept out of the shared reconcile path
so config sanitization semantics are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AlphaClaw assumed it was always the published @chrysb/alphaclaw npm
package: it resolved its own install dir and version by that exact
dependency key, and its in-place "Update" ran npm install
@chrysb/alphaclaw@latest from the registry. None of that holds when a
consumer pins it as a git dependency (e.g.
"alphaclaw": "git+https://github.com/<owner>/alphaclaw.git#main").

- Add lib/server/self-dependency.js: resolveSelfDependency() finds the
  consumer app root and how AlphaClaw is pinned, matching either the
  `alphaclaw` alias (git installs) or the `@chrysb/alphaclaw` npm scope,
  and classifies the spec as git vs npm (looksLikeGitDependency).
- Rename the package to `alphaclaw`.
- Route findInstallDir (openclaw-version + alphaclaw-version) and the
  template/version lookups through the shared resolver (dual-key).
- Self-update is now spec-aware: npm-pinned installs keep the in-place
  npm update (using the resolved package name, no hardcoded scope);
  git-pinned installs return redeploy/reinstall instructions instead and
  skip the npm registry version check entirely. The pending-update path
  in bin/alphaclaw.js does the same.
- Point the Render template + GitHub releases URLs at the garrytan fork.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Support git-based deployment of AlphaClaw
The boot-time prune added in the previous change lived in
ensureUsageTrackerPluginConfig, which only runs via runOnboardedBootSequence
— i.e. only when isOnboarded() is true. A deployment that carries a stale
@chrysb/alphaclaw usage-tracker path but is not (yet) onboarded never got
the path pruned, so OpenClaw kept rejecting the config and every openclaw
command failed.

bin/alphaclaw.js already has an unconditional "Config exists, reconciling
channels" block that runs on every boot whenever openclaw.json exists, and
it was *adding* the canonical usage-tracker path without removing stale ones
(leaving both). Prune stale `.../plugin/usage-tracker` entries there too, so
the migration is load-bearing regardless of onboarding state. The onboarded
reconcile prune remains as a backstop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Prune stale usage-tracker plugin paths on every boot
Latest npm stable. Brings Claude Fable 5 (registry-verified) and Haiku 4.5
model support, plus the 6.6 security-hardening batch (fail-closed exec
approvals, sandbox bind-path validation, MCP stdio/SSE hardening) and 6.8
admin-gating on HTTP model-override/session-kill endpoints.

Gateway is spawned with fixed args ("gateway run"), so the 6.8 CLI
usage-error exit-code change (0 -> non-zero) does not affect the watchdog's
exit-code handling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Latest npm stable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Current npm latest: the 2026.7.1 stabilization train (gateway crash-loop
recovery, fail-closed container upgrades, Sonnet 5 / Mythos 5 catalog)
plus the out-of-band 2026.7.1-2 hotfix for npm plugin updates (#108336).
Tarball diff against 2026.7.1 verified clean (same deps, no new install
scripts) since the hotfix skipped the upstream release pipeline.

OpenClaw 2026.7.1 moved normalizeThinkLevel into a thinking.shared-*.js
chunk that the sentinel scan never covered; add a fallback scan so the
thinking API resolves on both old and new dist layouts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
OpenClaw 2026.7.1 introduced two lifecycle behaviors the watchdog was blind
to:

1. Fatal config errors now exit with EX_CONFIG (78), meaning "do not
   restart until the config is fixed". The watchdog previously treated 78
   as a generic crash and restart-looped against that contract. It now
   enters a config_error lifecycle, attempts at most one auto-repair per
   incident (doctor --fix can genuinely fix config), never counts 78
   toward the crash-loop window, and pauses with a notification otherwise.
   Failing health probes no longer demote the config_error state.

2. The gateway's own crash-loop breaker can boot into control-plane-safe
   mode: /health stays green while channel autostart is suppressed, which
   previously read as fully healthy. The watchdog now probes /readyz after
   each healthy check, surfaces safeMode/suppressedChannels in status,
   notifies once per suppression set, and exposes
   POST /api/watchdog/resume-channels which issues the gateway's
   channels.start override per suppressed channel.

Covered by unit tests and an e2e suite driving the real watchdog through
the real routes against a stateful fake gateway.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ty, GPT-5.6.

Conflict resolutions:
- openclaw-thinking.js: take upstream's native thinking-level normalization
  (replaces our dist-chunk duck-typing fallback entirely).
- watchdog.js: adopt upstream's EX_CONFIG semantics (configuration_error
  lifecycle, latch until launch or forced repair, no auto-repair) over our
  one-shot-repair variant; keep our safe-mode /readyz detection and
  resume-channels API on top. Tests reconciled to upstream semantics.
- usage-tracker-config.js: keep both our stale-path pruning and their
  Telegram streaming migration.
- openclaw-version.js: keep both self-dependency resolution (git deploys)
  and their Node runtime gate.
- package.json: keep fork name 'alphaclaw' and openclaw@2026.7.1-2 pin
  (upstream pins plain 2026.7.1, which has the doctor --fix
  plugins.allow-stripping bug); adopt their 0.9.31 version.

Note: upstream's Node gate requires >=22.22.3 / >=24.15 / >=25.9 (SQLite WAL
corruption fix); suite verified on Node 24.18.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Systematic coverage push across the whole codebase, test files only (no
source changes): server core (chat-ws WebSocket bridge via a real ws
fake-gateway, gateway process supervision), all route surfaces (telegram,
nodes, webhooks, codex OAuth, browse with real temp git repos, models,
agents, doctor, system, onboarding), db layers (usage/webhooks/auth/doctor/
watchdog sqlite), gmail/google integration, cron service, cost/version
services, CLI helpers, and frontend lib/components (including preact
component logic tested via a hooks harness without a DOM).

Remaining uncovered lines (53 of 14,370) are documented dead code or
v8-to-istanbul instrumentation artifacts, verified per file by adversarial
inspection. Two small CLI scripts (lib/cli/git-sync.js,
lib/scripts/migrate-openclaw-codex.js) are not loaded by any test and sit
outside the measured set.

Also set vitest testTimeout to 30s: openclaw's plugin-sdk pays a >5s
first-import cost per worker, which flaked timing-sensitive files under
parallel load.

Full suite verified green four consecutive runs on Node 24.18.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… fix.

Conflict resolutions: keep fork name and openclaw@2026.7.1-2 pin, adopt
0.9.33; cron-service.test.js keeps both our coverage helpers and upstream's
SQLite cron-store harness. Adapted one coverage test to upstream's removal
of the cron delivery-mismatch warning (delivery.mode=none with a
message-tool prompt no longer warns).

Full suite green: 2,079 tests / 146 files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@chrysb chrysb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the OpenClaw 2026.7.1-2 and watchdog work. We can’t merge this PR as a whole because it also renames the published package, redirects release/template URLs to a fork, introduces git-deployment/update behavior, and adds a very large test-only expansion.

Please split out a narrowly scoped follow-up for the dependency hotfix and watchdog safe-mode/resume behavior (including its Watchdog UI). Keep the published package identity and official project/template URLs unchanged.

garrytan and others added 2 commits July 27, 2026 21:42
…files.

Adds retry:1 to the two proxy-over-real-socket test files that showed rare
transient connect races under parallel machine load (each passes 100% in
isolation; deterministic failures still fail both attempts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@garrytan

Copy link
Copy Markdown
Author

Thanks for the review — makes sense. Opened #110 with exactly the scoped subset you asked for: the 2026.7.1-2 dependency hotfix and the watchdog safe-mode/resume behavior including its Watchdog UI (safe-mode banner + resume action + badge state). Package identity and project/template URLs untouched. Closing this one.

@garrytan garrytan closed this Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants