Skip to content

fix(daemon,onboard): include webhook in supervised and launchable channel checks#5799

Merged
theonlyhennygod merged 1 commit intozeroclaw-labs:masterfrom
singlerider:fix/webhook-only-channel-supervisor
Apr 16, 2026
Merged

fix(daemon,onboard): include webhook in supervised and launchable channel checks#5799
theonlyhennygod merged 1 commit intozeroclaw-labs:masterfrom
singlerider:fix/webhook-only-channel-supervisor

Conversation

@singlerider
Copy link
Copy Markdown
Collaborator

Summary

  • has_supervised_channels() in crates/zeroclaw-runtime/src/daemon/mod.rs called channels_except_webhook(), so a webhook-only config never started the channel supervisor — the HTTP listener never bound to its port.
  • has_launchable_channels() in crates/zeroclaw-runtime/src/onboard/wizard.rs had the same bug: webhook-only configs never showed the "Launch channels now?" prompt after onboarding.
  • Both callsites changed from channels_except_webhook() to channels(), which includes webhook using the same is_some() check every other channel uses.
  • The wizard bug was found incidentally during investigation of the daemon bug. Same root cause, same fix, bundled here.

Label Snapshot

  • Risk label: risk: low
  • Size label: size: XS
  • Scope labels: runtime, onboard
  • Module labels: daemon:core, onboard:wizard, channel:webhook

Change Metadata

  • Change type: bug
  • Primary scope: runtime

Linked Issue

Validation Evidence

TDD approach: tests were written first and confirmed failing before the fix was applied, then confirmed passing after.

# Red — both fail before fix
cargo test -p zeroclaw-runtime webhook_only
# test daemon::tests::webhook_only_config_is_supervised ... FAILED
# test onboard::wizard::tests::webhook_only_config_is_launchable ... FAILED

# Green — both pass after fix
cargo test -p zeroclaw-runtime webhook_only
# test daemon::tests::webhook_only_config_is_supervised ... ok
# test onboard::wizard::tests::webhook_only_config_is_launchable ... ok

Attribution

@mn13's root cause analysis in #5798 was accurate and independently arrived at the same fix. The diagnosis (channels_except_webhook() as the culprit, channels() as the fix) matches exactly.

Note to @mn13

We do not run the webhook channel in our own setup, so end-to-end verification on a live webhook config falls to you. Please test this branch against your reproduction case from #5798 and confirm the Connection refused behavior is resolved before this merges.

Security Impact

  • New permissions or capabilities: No
  • New external network calls: No
  • Secrets or token handling changed: No
  • Attack surface changed: No — webhook startup behavior was already gated on explicit config; this only fixes the supervisor not starting when it should

Compatibility

  • Backward compatible: Yes
  • Config or env changes: No
  • Migration needed: No

Rollback Plan

git revert 6db79f98 — reverts both callsite changes and both tests in one commit.

… checks

has_supervised_channels() and has_launchable_channels() both called
channels_except_webhook(), causing webhook-only configs to never start
the channel supervisor and never show the launch prompt in the wizard.

Change both callsites to channels(), which includes webhook with the
same is_some() check used by every other channel.

Fixes zeroclaw-labs#5798
@singlerider singlerider force-pushed the fix/webhook-only-channel-supervisor branch from 1288a5d to 1abcb39 Compare April 16, 2026 09:20
@mn13
Copy link
Copy Markdown

mn13 commented Apr 16, 2026

Confirm, it resolves #5798

Copy link
Copy Markdown
Collaborator

@WareWolf-MoonWall WareWolf-MoonWall left a comment

Choose a reason for hiding this comment

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

Status: Approving. The fix is correct and the test discipline is excellent. Two conditional items need to be resolved before merge.


✅ The code change is right

channels() is defined as channels_except_webhook() + webhook appended. Using channels_except_webhook() in both has_supervised_channels() and has_launchable_channels() was therefore a logic error with an explicit name: the function says what it excludes. The one-character swap to channels() is the correct and complete fix at both callsites.

Bundling the wizard and daemon fixes is justified — same root cause, same predicate function, same fix — and the PR description explains the scope boundary clearly. The log message update ("No real-time channels""No channels") is accurate: the old phrasing encoded the assumption that webhook isn't "real-time," which is no longer how the predicate works.

After this merge, channels_except_webhook() will have no external callers — it will only be called from within channels() itself. That's a clean outcome. A non-blocking follow-up: consider marking it pub(crate) in zeroclaw-config to prevent a future contributor from reaching for it and re-introducing this exact class of bug. It's Beta tier so an API surface change needs its own deliberate commit, but the debt is worth labeling with a // TODO(debt): comment if not addressed immediately.

✅ TDD evidence is exactly right

Red → green with cargo test -p zeroclaw-runtime webhook_only is precisely the test discipline FND-006 §4.3 describes: "when you fix a bug, write a test that would have caught it." Both tests assert behaviour through the public predicate against a minimal webhook-only config — they will continue to pass if the implementation changes and break if the behaviour regresses. This is the pattern to repeat.

✅ Attribution and external confirmation

Naming @mn13's root-cause analysis in the PR body and asking them to test against their live reproduction before merge is exactly the ownership and collaboration the contribution culture RFC describes. The confirmation is on the record.


🟡 Conditional — apply labels before merge

gh pr view --json labels returns []. The Label Snapshot in the description names the right values (risk: low, size: XS, runtime, onboard, daemon:core, onboard:wizard, channel:webhook), but none of them are actually applied to the PR. The label taxonomy in FND-003 §9 and the Definition of Done expect them to be on the PR, not only in prose. Please apply them.

🟡 Conditional — five required template sections are absent

The PR description omits Privacy and Data Hygiene, i18n Follow-Through, Human Verification, Side Effects / Blast Radius, and Risks and Mitigations — all marked (required) in the template. The answers for this change are all trivially N/A or None, but the template is the project's Definition of Done checklist and skipping sections makes it harder to use as a review surface. Please add the missing sections with their N/A answers before merge.

@theonlyhennygod theonlyhennygod merged commit fe3ec58 into zeroclaw-labs:master Apr 16, 2026
20 checks passed
mn13 added a commit to mn13/zeroclaw that referenced this pull request Apr 17, 2026
After the rebase onto master, two WebhookConfig { ... } struct literals
added in fe3ec58 (zeroclaw-labs#5799) no longer compile without the three retry
fields introduced in dd93422. Both are test-only call-sites, so `None`
is correct for each.
whtiehack added a commit to whtiehack/zeroclaw that referenced this pull request Apr 18, 2026
has_supervised_channels 和 has_launchable_channels 之前都调
channels_except_webhook(),导致 webhook-only 配置:
- daemon 启动时不拉起 channel supervisor
- onboard wizard 不显示 launch 提示

两处都改成 channels(),和其它 channel 共享同一个 is_some() 判定。

Ports upstream fe3ec58 (zeroclaw-labs#5799) to master_wecom's
pre-workspace-split layout.

Co-authored-by: Shane Engelman <contact@shane.gg>
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.

Webhook channel doesn't start without another channel configured

4 participants