@sellable/install 0.1.319 → 0.1.321
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HERMES-SLACK-PROFILE-SCOPING.md +44 -146
- package/README.md +20 -103
- package/bin/sellable-install.mjs +13 -20
- package/package.json +1 -1
- package/skill-templates/refill-sends.md +0 -4
|
@@ -1,169 +1,67 @@
|
|
|
1
1
|
# Hermes Slack Profile Scoping
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
## Default Rule
|
|
7
|
-
|
|
8
|
-
For Sellable-managed customer channels, use one dedicated Slack app/token pair
|
|
9
|
-
per active Hermes customer profile. Run native `hermes -p <profile> gateway run`
|
|
10
|
-
for that profile only. Do not run multiple active Hermes profile gateways
|
|
11
|
-
against the same `SLACK_APP_TOKEN`.
|
|
12
|
-
|
|
13
|
-
The customer's Slack app is bound to the exact Slack channel id and the
|
|
14
|
-
customer's profile-local Sellable MCP config. Customer profiles must not store
|
|
15
|
-
or read Sellable Admin MCP credentials, admin Slack app tokens, or sibling
|
|
16
|
-
profile config.
|
|
17
|
-
|
|
18
|
-
The shared dispatcher remains a fallback/research path only. Use it only when
|
|
19
|
-
Sellable Admin explicitly owns one shared listener and route registry.
|
|
20
|
-
|
|
21
|
-
The 2026-07-06 Hostinger POC proved the native Hermes listener for the
|
|
22
|
-
`sellable-admin` profile with the existing `Sellable Reply Bot` app in
|
|
23
|
-
`#team-chat`: a human mention produced a new Hermes session and a threaded bot
|
|
24
|
-
reply. Treat that as proof that the gateway/listener path works for one owning
|
|
25
|
-
profile, not as approval for multiple active customer profiles sharing one app
|
|
3
|
+
Sellable customer profiles use one dedicated native Slack app/token pair, one
|
|
4
|
+
workspace-locked plain Sellable MCP, and one native Hermes s6 gateway. There is
|
|
5
|
+
no shared dispatcher, route registry, listener fallback, or shared customer app
|
|
26
6
|
token.
|
|
27
7
|
|
|
28
|
-
The
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
hermes --profile acme send --to slack:C0BFERDV3N0 --subject '[Hermes acme smoke]' ...
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
That succeeded and is useful as an internal smoke test. It does not change the
|
|
36
|
-
inbound listener rule: each active customer profile needs its own native Slack
|
|
37
|
-
app token pair unless Sellable Admin deliberately chooses the dispatcher
|
|
38
|
-
fallback.
|
|
39
|
-
|
|
40
|
-
## Which Slack Values Are Enough
|
|
41
|
-
|
|
42
|
-
For outbound sends and ordinary Slack Web API calls, the important value is the
|
|
43
|
-
profile-local `SLACK_BOT_TOKEN`.
|
|
44
|
-
|
|
45
|
-
For native Hermes live listening through Slack Socket Mode, the profile also
|
|
46
|
-
needs `SLACK_APP_TOKEN`, an app-level `xapp-...` token with `connections:write`.
|
|
47
|
-
`SLACK_APP_ID`, `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET`,
|
|
48
|
-
`SLACK_SIGNING_SECRET`, `SLACK_VERIFICATION_TOKEN`, `SLACK_TEAM_ID`, and
|
|
49
|
-
`SLACK_OPERATOR_EMAIL` do not replace `SLACK_APP_TOKEN`.
|
|
50
|
-
|
|
51
|
-
## Required Slack App Shape
|
|
52
|
-
|
|
53
|
-
Outbound Slack sends can work with fewer permissions. Native Hermes inbound
|
|
54
|
-
listening needs the Slack app itself to be configured for Socket Mode and event
|
|
55
|
-
delivery:
|
|
8
|
+
The production Sellable Reply Bot remains separate HTTP-interactivity product
|
|
9
|
+
infrastructure. Keep Socket Mode off and keep its request URL at
|
|
10
|
+
`https://app.sellable.dev/api/v2/slack/interactions`.
|
|
56
11
|
|
|
57
|
-
|
|
58
|
-
- Create an app-level token with `connections:write`.
|
|
59
|
-
- Install the bot with `app_mentions:read`, `channels:history`,
|
|
60
|
-
`channels:read`, `chat:write`, `groups:history`, `groups:read`,
|
|
61
|
-
`im:history`, `im:read`, `mpim:history`, `mpim:read`, and `users:read`.
|
|
62
|
-
- Subscribe bot events for `app_mention`, `message.channels`,
|
|
63
|
-
`message.groups`, `message.im`, and `message.mpim`.
|
|
64
|
-
- Reinstall the app after changing scopes or event subscriptions.
|
|
12
|
+
## Public Boundary
|
|
65
13
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
not replace `SLACK_ALLOWED_CHANNELS`; keep the profile-local allowlist explicit.
|
|
69
|
-
|
|
70
|
-
## Profile Bootstrap Command
|
|
71
|
-
|
|
72
|
-
Use the Sellable installer profile bootstrap:
|
|
14
|
+
Customer onboarding is owned by the Sellable Admin native-app skill through one
|
|
15
|
+
public command:
|
|
73
16
|
|
|
74
17
|
```bash
|
|
75
|
-
sellable hermes
|
|
76
|
-
--profile acme \
|
|
77
|
-
--profiles-root /srv/hermes/profiles \
|
|
78
|
-
--workspace-id ws_acme \
|
|
79
|
-
--workspace-name Acme \
|
|
80
|
-
--token-file /run/secrets/sellable-acme-token \
|
|
81
|
-
--slack-bot-token "$SLACK_BOT_TOKEN" \
|
|
82
|
-
--slack-app-token "$SLACK_APP_TOKEN" \
|
|
83
|
-
--slack-home-channel C0ACME12345 \
|
|
84
|
-
--slack-home-channel-name sellable-acme \
|
|
85
|
-
--slack-allowed-users U0OPERATOR1 \
|
|
86
|
-
--slack-require-mention true \
|
|
87
|
-
--json
|
|
18
|
+
sellable-admin-install hermes customer bootstrap --mode <mode> [approved inputs]
|
|
88
19
|
```
|
|
89
20
|
|
|
90
|
-
|
|
91
|
-
the
|
|
92
|
-
|
|
21
|
+
The operator uses read-only `plan`, then approved `apply`, and later
|
|
22
|
+
`resume|status|verify|rebuild|rollback` with the persisted `runId`. Do not ask
|
|
23
|
+
the operator to coordinate the public Sellable installer, Slack API/CLI,
|
|
24
|
+
cloud-browser, Gmail, profile, or gateway internals separately.
|
|
93
25
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
26
|
+
The approval packet binds exact team/workspace/channel/profile/user identity,
|
|
27
|
+
customer Sellable token-file ref, `gpt-5.6-sol`, redacted evidence root, and the
|
|
28
|
+
exact tested Admin install/MCP and Sellable install/MCP candidates plus all four
|
|
29
|
+
SHA-256 values.
|
|
97
30
|
|
|
98
|
-
##
|
|
31
|
+
## Public Sellable Installer Role
|
|
99
32
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
```env
|
|
104
|
-
SLACK_BOT_TOKEN=...
|
|
105
|
-
SLACK_APP_TOKEN=...
|
|
106
|
-
SLACK_HOME_CHANNEL=C0ACME12345
|
|
107
|
-
SLACK_HOME_CHANNEL_NAME=sellable-acme
|
|
108
|
-
SLACK_ALLOWED_CHANNELS=C0ACME12345
|
|
109
|
-
SLACK_ALLOWED_USERS=U0OPERATOR1
|
|
110
|
-
SLACK_REQUIRE_MENTION=true
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
Keep the file mode at `0600`. Do not copy raw tokens into planning docs, chat,
|
|
114
|
-
or committed artifacts. Record token fingerprints only.
|
|
115
|
-
|
|
116
|
-
The profile's Hermes MCP env must also include the profile-local Sellable
|
|
117
|
-
config, customer workspace lock, and fail-closed guard:
|
|
33
|
+
The Admin factory calls the pinned `@sellable/install` candidate internally and
|
|
34
|
+
passes the pinned `@sellable/mcp` candidate through `--mcp-package`. The public
|
|
35
|
+
installer writes profile-local Sellable config and Hermes MCP env with:
|
|
118
36
|
|
|
119
37
|
```yaml
|
|
120
|
-
SELLABLE_CONFIG_PATH: /
|
|
121
|
-
SELLABLE_CONFIGS_DIR: /
|
|
122
|
-
SELLABLE_LOCK_WORKSPACE_ID:
|
|
38
|
+
SELLABLE_CONFIG_PATH: /opt/data/profiles/<customerSlug>/sellable/config.json
|
|
39
|
+
SELLABLE_CONFIGS_DIR: /opt/data/profiles/<customerSlug>/sellable/configs
|
|
40
|
+
SELLABLE_LOCK_WORKSPACE_ID: <approvedWorkspaceId>
|
|
123
41
|
SELLABLE_REQUIRE_WORKSPACE_LOCK: "1"
|
|
124
42
|
```
|
|
125
43
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
admin config state. Only the `sellable-admin` profile should provision,
|
|
129
|
-
inspect, or repair other profiles.
|
|
130
|
-
|
|
131
|
-
For the shared dispatcher model, do not copy the shared `SLACK_BOT_TOKEN` or
|
|
132
|
-
`SLACK_APP_TOKEN` into customer profile `.env` files. The dispatcher owns those
|
|
133
|
-
tokens and route metadata decides the customer profile.
|
|
44
|
+
It does not create Slack apps, handle Slack tokens, install Admin MCP, or choose
|
|
45
|
+
the profile/workspace/channel from prompt text.
|
|
134
46
|
|
|
135
|
-
##
|
|
136
|
-
|
|
137
|
-
The shared Slack dispatcher and its route registry are fallback Sellable Admin
|
|
138
|
-
surfaces. This customer-facing installer must not create shared route bundles or
|
|
139
|
-
write shared listener tokens. Sellable Admin owns Slack app creation and profile
|
|
140
|
-
provisioning, then calls this installer for profile-local Sellable runtime
|
|
141
|
-
bootstrap inside the already-provisioned Hermes profile.
|
|
142
|
-
|
|
143
|
-
## Verification
|
|
144
|
-
|
|
145
|
-
Run the installer and dispatcher UAT before publishing installer changes:
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
npm run test:unit -- tests/install-package/agent-preferences.test.ts
|
|
149
|
-
scripts/run-phase92-hermes-profile-bootstrap-uat.sh --mode local-temp
|
|
150
|
-
scripts/run-phase92-hermes-profile-bootstrap-uat.sh --mode linux-shaped
|
|
151
|
-
scripts/run-phase031-hermes-slack-dispatcher-uat.sh --mode local-fixture
|
|
152
|
-
```
|
|
47
|
+
## Customer Isolation
|
|
153
48
|
|
|
154
|
-
|
|
49
|
+
Customer profiles are blank-created. They contain:
|
|
155
50
|
|
|
156
|
-
- profile-local
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
- `
|
|
160
|
-
-
|
|
51
|
+
- dedicated profile-local Slack runtime secrets in mode-`0600` storage
|
|
52
|
+
- exact channel and allowed-human ID allowlists
|
|
53
|
+
- customer-safe manifest with no slash/App Home/assistant/DM/MPIM surfaces
|
|
54
|
+
- the current `openai-codex` `gpt-5.6-sol` model object
|
|
55
|
+
- Hermes root OAuth fallback from `/opt/data/auth.json`
|
|
56
|
+
- pinned plain Sellable MCP locked to one approved workspace
|
|
57
|
+
- one profile-specific native s6 gateway
|
|
161
58
|
|
|
162
|
-
|
|
59
|
+
They never contain customer-local `auth.json`, provider pools, OpenRouter/raw
|
|
60
|
+
OpenAI keys, Sellable Admin MCP/admin skills, browser/Gmail/provisioning
|
|
61
|
+
credentials, TOTP material, or sibling data.
|
|
163
62
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
edits, or untracked processes.
|
|
63
|
+
Direct MCP proof before gateway start must show one intended active/visible
|
|
64
|
+
workspace, `siblingInventoryFetched=false`, and no Admin MCP. Slack acceptance
|
|
65
|
+
then requires real API/CLI, secret-file, s6 process, same-thread reply,
|
|
66
|
+
negative-isolation, restart, rollback, rebuild, and redaction receipts tied to
|
|
67
|
+
the immutable package hashes.
|
package/README.md
CHANGED
|
@@ -83,120 +83,37 @@ Auth is stored once at:
|
|
|
83
83
|
~/.sellable/config.json
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
## Hermes
|
|
86
|
+
## Hermes Customer Profiles
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
instead of the global `~/.sellable/config.json`:
|
|
88
|
+
Customer onboarding is owned by the Sellable Admin native customer bootstrap:
|
|
90
89
|
|
|
91
90
|
```bash
|
|
92
|
-
|
|
93
|
-
sellable --host hermes \
|
|
94
|
-
--sellable-config-path "$profile/sellable/config.json" \
|
|
95
|
-
--sellable-configs-dir "$profile/sellable/configs"
|
|
91
|
+
sellable-admin-install hermes customer bootstrap --mode <mode> [approved inputs]
|
|
96
92
|
```
|
|
97
93
|
|
|
98
|
-
That
|
|
99
|
-
`
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
That command is the sole operator-facing interface. It calls the exact pinned
|
|
95
|
+
`@sellable/install` tarball internally and passes the exact pinned
|
|
96
|
+
`@sellable/mcp` tarball through `--mcp-package`. Do not ask an operator to run
|
|
97
|
+
the public installer, supply Slack tokens in argv, edit profile files, or manage
|
|
98
|
+
the gateway as separate onboarding steps.
|
|
102
99
|
|
|
103
|
-
|
|
100
|
+
The internal profile stage writes profile-local Sellable paths and the exact
|
|
101
|
+
workspace boundary:
|
|
104
102
|
|
|
105
|
-
```
|
|
106
|
-
sellable
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
--workspace-name Acme \
|
|
111
|
-
--token-file /run/secrets/sellable-acme-token \
|
|
112
|
-
--json
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
It creates:
|
|
116
|
-
|
|
117
|
-
```text
|
|
118
|
-
/srv/hermes/profiles/acme/config.yaml
|
|
119
|
-
/srv/hermes/profiles/acme/sellable/config.json
|
|
120
|
-
/srv/hermes/profiles/acme/sellable/configs/
|
|
121
|
-
/srv/hermes/profiles/acme/skills/sellable/
|
|
122
|
-
/srv/hermes/profiles/acme/.env # only when Slack token inputs are supplied
|
|
103
|
+
```yaml
|
|
104
|
+
SELLABLE_CONFIG_PATH: /opt/data/profiles/<customerSlug>/sellable/config.json
|
|
105
|
+
SELLABLE_CONFIGS_DIR: /opt/data/profiles/<customerSlug>/sellable/configs
|
|
106
|
+
SELLABLE_LOCK_WORKSPACE_ID: <approvedWorkspaceId>
|
|
107
|
+
SELLABLE_REQUIRE_WORKSPACE_LOCK: "1"
|
|
123
108
|
```
|
|
124
109
|
|
|
125
|
-
|
|
126
|
-
`
|
|
127
|
-
|
|
128
|
-
Sellable MCP requests are forced to that workspace, workspace switching/creation
|
|
129
|
-
is blocked, workspace listings are filtered, and a missing lock fails closed
|
|
130
|
-
instead of falling back to shared/admin config. Use the `sellable-admin` profile
|
|
131
|
-
for provisioning or cross-profile inspection.
|
|
110
|
+
The locked MCP requests only the approved workspace, blocks workspace switching
|
|
111
|
+
and creation, and reports `siblingInventoryFetched=false`. The customer profile
|
|
112
|
+
must contain no Admin MCP, admin token, customer-local OAuth, or sibling config.
|
|
132
113
|
|
|
133
114
|
See [`HERMES-SLACK-PROFILE-SCOPING.md`](./HERMES-SLACK-PROFILE-SCOPING.md) for
|
|
134
|
-
the
|
|
135
|
-
|
|
136
|
-
If no token is supplied, bootstrap still creates a pending
|
|
137
|
-
`sellable/config.json` so the profile path is concrete from the first MCP
|
|
138
|
-
launch. Finish auth with:
|
|
139
|
-
|
|
140
|
-
```bash
|
|
141
|
-
sellable auth set <token> --workspace-id <workspace_id> \
|
|
142
|
-
--sellable-config-path /srv/hermes/profiles/acme/sellable/config.json
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Slack Socket Mode tokens can be written profile-locally:
|
|
146
|
-
|
|
147
|
-
```bash
|
|
148
|
-
sellable hermes profile bootstrap \
|
|
149
|
-
--profile acme \
|
|
150
|
-
--profiles-root /srv/hermes/profiles \
|
|
151
|
-
--workspace-id ws_acme \
|
|
152
|
-
--slack-bot-token "$SLACK_BOT_TOKEN" \
|
|
153
|
-
--slack-app-token "$SLACK_APP_TOKEN"
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
The Slack app must also be configured for inbound Socket Mode delivery. Outbound
|
|
157
|
-
Slack Web API sends can work before this is complete, but Hermes will not hear
|
|
158
|
-
mentions until the app has Socket Mode enabled, an app-level token with
|
|
159
|
-
`connections:write`, bot scopes/events for `app_mention` plus channel/group/IM
|
|
160
|
-
message events, and a fresh workspace reinstall after scope or event changes.
|
|
161
|
-
|
|
162
|
-
Scope the profile to its customer channel at install time:
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
sellable hermes profile bootstrap \
|
|
166
|
-
--profile acme \
|
|
167
|
-
--profiles-root /srv/hermes/profiles \
|
|
168
|
-
--workspace-id ws_acme \
|
|
169
|
-
--slack-bot-token "$SLACK_BOT_TOKEN" \
|
|
170
|
-
--slack-app-token "$SLACK_APP_TOKEN" \
|
|
171
|
-
--slack-home-channel C0ACME12345 \
|
|
172
|
-
--slack-home-channel-name sellable-acme \
|
|
173
|
-
--slack-allowed-users U0OPERATOR1 \
|
|
174
|
-
--slack-require-mention true
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
When `--slack-home-channel` is supplied without
|
|
178
|
-
`--slack-allowed-channels`, bootstrap writes
|
|
179
|
-
`SLACK_ALLOWED_CHANNELS=<home-channel-id>` too. That fail-closes a customer
|
|
180
|
-
profile to the intended channel by default. Use
|
|
181
|
-
`--slack-allowed-channels C...,G...` only when a profile is deliberately allowed
|
|
182
|
-
to listen in multiple channels. Pass channel IDs, not `#channel-name`, and use
|
|
183
|
-
separate Slack bot/app tokens per customer profile when you need hard isolation
|
|
184
|
-
between concurrently listening Hermes profiles.
|
|
185
|
-
|
|
186
|
-
Customer profiles should use customer-scoped Sellable credentials. A shared
|
|
187
|
-
Sellable admin token can work for internal admin automation, but it is weaker
|
|
188
|
-
isolation and should not be the default for customer profiles. After changing
|
|
189
|
-
Hermes profile config, restart the gateway/session or run `/reload-mcp` and
|
|
190
|
-
`/reload-skills`.
|
|
191
|
-
|
|
192
|
-
Validate the active profile with the same path inputs:
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
SELLABLE_CONFIG_PATH=/srv/hermes/profiles/acme/sellable/config.json \
|
|
196
|
-
SELLABLE_CONFIGS_DIR=/srv/hermes/profiles/acme/sellable/configs \
|
|
197
|
-
sellable --verify-only --host hermes --json \
|
|
198
|
-
--artifact /srv/hermes/profiles/acme/sellable/verify-runtime.json
|
|
199
|
-
```
|
|
115
|
+
the dedicated native Slack app, root OAuth fallback, immutable package, s6
|
|
116
|
+
gateway, rebuild, and live UAT contract.
|
|
200
117
|
|
|
201
118
|
Claude Code, Codex, and Hermes are configured to launch the same packaged MCP server. The
|
|
202
119
|
installer also writes Sellable agent definitions from the packaged `agents/`
|
package/bin/sellable-install.mjs
CHANGED
|
@@ -213,26 +213,19 @@ Auth:
|
|
|
213
213
|
also pass --sellable-config-path or set SELLABLE_CONFIG_PATH so auth and MCP
|
|
214
214
|
runtime use the same profile-local config file.
|
|
215
215
|
|
|
216
|
-
Hermes profile
|
|
217
|
-
|
|
218
|
-
sellable hermes
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
lock is later removed or not yet provisioned.
|
|
230
|
-
|
|
231
|
-
Hermes shared Slack dispatcher:
|
|
232
|
-
Shared listener setup and route-registry validation are internal Sellable
|
|
233
|
-
Admin responsibilities. This customer-facing installer only bootstraps a
|
|
234
|
-
profile-local Sellable runtime after Sellable Admin provisions the profile
|
|
235
|
-
and dispatcher route.
|
|
216
|
+
Hermes customer profile stage:
|
|
217
|
+
Managed customer onboarding uses only:
|
|
218
|
+
sellable-admin-install hermes customer bootstrap --mode <mode> [approved inputs]
|
|
219
|
+
|
|
220
|
+
The Admin state machine invokes this package's profile bootstrap internally
|
|
221
|
+
with exact token-file, workspace-lock, profile-root, and --mcp-package inputs.
|
|
222
|
+
Operators must not use the low-level profile command to coordinate Slack,
|
|
223
|
+
profile, or gateway onboarding manually. Customer profiles use root Codex
|
|
224
|
+
OAuth fallback and contain no local auth.json, provider pool, or Admin MCP.
|
|
225
|
+
|
|
226
|
+
Hermes customer Slack runtime:
|
|
227
|
+
Each customer profile uses its own dedicated native Slack app and gateway.
|
|
228
|
+
Sellable Admin owns the single resumable customer bootstrap interface.
|
|
236
229
|
`;
|
|
237
230
|
}
|
|
238
231
|
|
package/package.json
CHANGED
|
@@ -276,10 +276,6 @@ need raw proof, call the read-only `get_scheduler_fill_capacity` query for the
|
|
|
276
276
|
same sender/action/date; it tells the MCP how many cells the product scheduler
|
|
277
277
|
will try to place and does not import, approve, schedule, refresh credits, or
|
|
278
278
|
mutate.
|
|
279
|
-
Treat `rollingWeeklyInvite.capacityFreedDuringWindow:true` as proof that
|
|
280
|
-
rolling-weekly capacity frees later in the send window and remains schedulable;
|
|
281
|
-
use its timing fields instead of treating the window-start gate as a permanent
|
|
282
|
-
full-day blocker.
|
|
283
279
|
When the refill loop has ready rows and needs scheduler pickup now, use
|
|
284
280
|
`run_scheduler_sweep` with the same explicit `workspaceId`; it can place cells
|
|
285
281
|
within existing scheduler gates and returns the receipt, but it never sends or
|