Summary
Slack messaging channel configuration can survive a sandbox rebuild while the required slack network policy preset is not present on the recreated sandbox. The result is a sandbox that appears Slack-configured (openclaw.json contains Slack account config and provider placeholders), but Slack cannot connect because egress to Slack endpoints is missing/denied.
This is distinct from the OpenShell credential-placeholder issue and from Slack authorization bugs. It is a NemoClaw lifecycle/state consistency issue: channel state and policy state can drift across rebuild/resume.
Why this matters
This blocks reproducing and validating Slack behavior such as #3729 because the test never reaches Slack event handling. Before a DM or channel @mention can test allowlist behavior, Socket Mode must connect and receive events. If Slack config exists but the Slack policy preset is absent, the user sees Slack enabled/configured but no inbound messages arrive.
Observed evidence from fresh Percy/Spark setup
Environment:
- Host: DGX Spark (
sparky)
- NemoClaw: v0.0.39
- OpenShell CLI/gateway: 0.0.37
- OpenClaw in sandbox: v2026.4.24
- Sandbox:
percy
- Messaging channel: Slack
- Slack app/workspace configured with Socket Mode and Event Subscriptions (
message.im, app_mention)
After a rebuild/resume, Percy was Ready and Slack config still existed inside the sandbox:
"channels": {
"defaults": {},
"slack": {
"accounts": {
"default": {
"botToken": "xoxb-OPENSHELL-RESOLVE-ENV-SLACK_BOT_TOKEN",
"enabled": true,
"appToken": "xapp-OPENSHELL-RESOLVE-ENV-SLACK_APP_TOKEN"
}
}
}
}
But nemoclaw percy status listed policies without slack:
Policies: npm, pypi, huggingface, brew, brave, local-inference
Slack provider logs then showed repeated provider startup failures while attempting Socket Mode startup, e.g. HTTP 403s on Slack calls and failure to retrieve the WSS URL. Earlier in the same setup, after manually applying the Slack policy, Slack API health calls were allowed by the slack policy.
Code evidence / likely drift point
The code currently tracks messaging channels and applied policy presets separately:
src/lib/onboard/initial-policy.ts
CREATE_TIME_POLICY_PRESETS_BY_CHANNEL maps slack -> slack.
prepareInitialSandboxCreatePolicy(basePolicyPath, activeMessagingChannels, ...) merges create-time presets only from activeMessagingChannels.
src/lib/onboard.ts
- Computes
activeMessagingChannels from token/reuse state.
- Registers runtime metadata separately:
policies: initialSandboxPolicy.appliedPresets
messagingChannels: ...
src/lib/actions/sandbox/rebuild.ts
- Rebuild backs up/deletes the sandbox, stashes messaging channels into the onboard session, then calls
onboard({ resume: true, nonInteractive: true, recreateSandbox: true }).
- After onboard, it preserves
messagingChannels / disabledChannels / credential hashes, but policy preservation depends on the create-time policy path and registry/session state being recomputed correctly.
The observed failure mode is that Slack channel config is regenerated/restored, but the create-time policy for Slack is not present in the live sandbox policy and the registry status no longer shows slack.
Reproduction plan for a new session
Use a real Slack app/workspace or a test Slack app with valid tokens. The bug is about policy/config drift, so inbound Slack messages are not required to prove the core issue.
-
Fresh onboard a sandbox with Slack enabled:
nemoclaw onboard
# choose local or any working inference provider
# select Slack messaging
# provide valid SLACK_BOT_TOKEN and SLACK_APP_TOKEN
-
Confirm initial state is consistent:
nemoclaw <sandbox> status
openshell policy get --full <sandbox> | grep -i slack
docker exec <container> sh -lc 'grep -n "slack" -A12 -B2 /sandbox/.openclaw/openclaw.json'
Expected initial good state:
nemoclaw <sandbox> status includes slack in Policies.
- live OpenShell policy contains Slack endpoints (
slack.com, api.slack.com, wss-primary.slack.com, wss-backup.slack.com, etc.).
/sandbox/.openclaw/openclaw.json contains Slack channel config.
-
Trigger rebuild lifecycle:
nemoclaw <sandbox> rebuild --yes
Alternative paths worth testing because they use rebuild/resume semantics:
nemoclaw <sandbox> channels add slack
nemoclaw <sandbox> channels remove slack then add again
- interrupted rebuild followed by
nemoclaw onboard --resume
-
Re-check state:
nemoclaw <sandbox> status
openshell policy get --full <sandbox> | grep -i slack
docker exec <new-container> sh -lc 'grep -n "slack" -A12 -B2 /sandbox/.openclaw/openclaw.json'
-
Bug condition:
openclaw.json still contains Slack channel config, but
nemoclaw <sandbox> status does not list slack, or
openshell policy get --full <sandbox> lacks Slack network policy entries.
Expected behavior
If Slack messaging is configured/enabled after a rebuild, the recreated sandbox must include the Slack network policy preset at creation time or reapply it immediately after creation.
The invariant should be:
Slack channel enabled/configured implies Slack egress policy present.
This should hold across:
- initial onboard
nemoclaw <sandbox> rebuild
nemoclaw onboard --resume
channels add/remove/start/stop flows that rebuild the sandbox
- credential rotation rebuilds
Acceptance criteria / done definition
- Add regression coverage for the rebuild path showing that a sandbox with
messagingChannels: ["slack"] is recreated with the slack policy preset.
- After
nemoclaw <sandbox> rebuild --yes, both are true:
- Slack channel config remains present in
/sandbox/.openclaw/openclaw.json.
- live OpenShell policy contains the
slack network policy entries.
nemoclaw <sandbox> status reports slack in Policies when Slack messaging is configured.
- No manual
nemoclaw <sandbox> policy-add slack is required after rebuild.
- Existing channel stop/remove semantics remain intact: if Slack is intentionally removed/stopped, the policy should not be silently re-granted unless the configured active channel state requires it.
Related but distinct issues
Summary
Slack messaging channel configuration can survive a sandbox rebuild while the required
slacknetwork policy preset is not present on the recreated sandbox. The result is a sandbox that appears Slack-configured (openclaw.jsoncontains Slack account config and provider placeholders), but Slack cannot connect because egress to Slack endpoints is missing/denied.This is distinct from the OpenShell credential-placeholder issue and from Slack authorization bugs. It is a NemoClaw lifecycle/state consistency issue: channel state and policy state can drift across rebuild/resume.
Why this matters
This blocks reproducing and validating Slack behavior such as #3729 because the test never reaches Slack event handling. Before a DM or channel
@mentioncan test allowlist behavior, Socket Mode must connect and receive events. If Slack config exists but the Slack policy preset is absent, the user sees Slack enabled/configured but no inbound messages arrive.Observed evidence from fresh Percy/Spark setup
Environment:
sparky)percymessage.im,app_mention)After a rebuild/resume, Percy was Ready and Slack config still existed inside the sandbox:
But
nemoclaw percy statuslisted policies withoutslack:Slack provider logs then showed repeated provider startup failures while attempting Socket Mode startup, e.g. HTTP 403s on Slack calls and failure to retrieve the WSS URL. Earlier in the same setup, after manually applying the Slack policy, Slack API health calls were allowed by the
slackpolicy.Code evidence / likely drift point
The code currently tracks messaging channels and applied policy presets separately:
src/lib/onboard/initial-policy.tsCREATE_TIME_POLICY_PRESETS_BY_CHANNELmapsslack->slack.prepareInitialSandboxCreatePolicy(basePolicyPath, activeMessagingChannels, ...)merges create-time presets only fromactiveMessagingChannels.src/lib/onboard.tsactiveMessagingChannelsfrom token/reuse state.policies: initialSandboxPolicy.appliedPresetsmessagingChannels: ...src/lib/actions/sandbox/rebuild.tsonboard({ resume: true, nonInteractive: true, recreateSandbox: true }).messagingChannels/disabledChannels/ credential hashes, but policy preservation depends on the create-time policy path and registry/session state being recomputed correctly.The observed failure mode is that Slack channel config is regenerated/restored, but the create-time policy for Slack is not present in the live sandbox policy and the registry status no longer shows
slack.Reproduction plan for a new session
Use a real Slack app/workspace or a test Slack app with valid tokens. The bug is about policy/config drift, so inbound Slack messages are not required to prove the core issue.
Fresh onboard a sandbox with Slack enabled:
Confirm initial state is consistent:
Expected initial good state:
nemoclaw <sandbox> statusincludesslackin Policies.slack.com,api.slack.com,wss-primary.slack.com,wss-backup.slack.com, etc.)./sandbox/.openclaw/openclaw.jsoncontains Slack channel config.Trigger rebuild lifecycle:
Alternative paths worth testing because they use rebuild/resume semantics:
nemoclaw <sandbox> channels add slacknemoclaw <sandbox> channels remove slackthen add againnemoclaw onboard --resumeRe-check state:
Bug condition:
openclaw.jsonstill contains Slack channel config, butnemoclaw <sandbox> statusdoes not listslack, oropenshell policy get --full <sandbox>lacks Slack network policy entries.Expected behavior
If Slack messaging is configured/enabled after a rebuild, the recreated sandbox must include the Slack network policy preset at creation time or reapply it immediately after creation.
The invariant should be:
This should hold across:
nemoclaw <sandbox> rebuildnemoclaw onboard --resumechannels add/remove/start/stopflows that rebuild the sandboxAcceptance criteria / done definition
messagingChannels: ["slack"]is recreated with theslackpolicy preset.nemoclaw <sandbox> rebuild --yes, both are true:/sandbox/.openclaw/openclaw.json.slacknetwork policy entries.nemoclaw <sandbox> statusreportsslackin Policies when Slack messaging is configured.nemoclaw <sandbox> policy-add slackis required after rebuild.Related but distinct issues
@mentionauthorization/allowlist behavior. This policy drift blocks reaching that behavior.