@sellable/install 0.1.433-wip.146.20260728134200 → 0.1.433
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/bin/sellable-install.mjs +0 -3
- package/container/Dockerfile +4 -4
- package/container/README.md +2 -2
- package/lib/sellable-agent/fly-customer-image/Dockerfile +3 -3
- package/lib/sellable-agent/fly-customer-image/customer-runtime.mjs +17 -14
- package/lib/sellable-agent/fly-customer-model.mjs +43 -0
- package/lib/sellable-agent/host-bootstrap.mjs +1 -1
- package/lib/sellable-agent/host-worker.mjs +1 -1
- package/lib/sellable-agent/profile-materializer.mjs +1 -1
- package/lib/sellable-agent/provisioning-adapter.mjs +4 -4
- package/package.json +1 -1
- package/skill-templates/refill-sends.md +6 -74
package/bin/sellable-install.mjs
CHANGED
|
@@ -1194,9 +1194,6 @@ const CREATE_EVERGREEN_CAMPAIGNS_ALLOWED_TOOLS = [
|
|
|
1194
1194
|
];
|
|
1195
1195
|
|
|
1196
1196
|
const REFILL_SENDS_ALLOWED_TOOLS = [
|
|
1197
|
-
"mcp__sellable__refill_v3_sender_date_eligibility",
|
|
1198
|
-
"mcp__sellable__refill_v3_supply_assessment",
|
|
1199
|
-
"mcp__sellable__refill_v3_workspace_inventory",
|
|
1200
1197
|
"mcp__sellable__refill_sends",
|
|
1201
1198
|
"mcp__sellable__get_auth_status",
|
|
1202
1199
|
"mcp__sellable__start_cli_login",
|
package/container/Dockerfile
CHANGED
|
@@ -3,12 +3,12 @@ FROM ${HERMES_IMAGE}
|
|
|
3
3
|
|
|
4
4
|
USER root
|
|
5
5
|
|
|
6
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
6
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.433
|
|
7
7
|
ARG MCP_PACKAGE=@sellable/mcp@0.1.760-wip.phase143.20260727100513
|
|
8
8
|
ARG INSTALLER_INTEGRITY
|
|
9
9
|
ARG MCP_INTEGRITY=sha512-muNXHuRnLTfsnW+MQUvK+p0VBZETDKeevr70iRliXyqE3/SLrZQJLL1laJzMo+qiUs9jMXMHdKOQfQqLiwJvtg==
|
|
10
10
|
|
|
11
|
-
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.
|
|
11
|
+
RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.433" \
|
|
12
12
|
&& test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.760-wip.phase143.20260727100513" \
|
|
13
13
|
&& test -n "${INSTALLER_INTEGRITY}" \
|
|
14
14
|
&& test "$(npm view "${INSTALLER_PACKAGE}" dist.integrity)" = "${INSTALLER_INTEGRITY}" \
|
|
@@ -23,9 +23,9 @@ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.430" \
|
|
|
23
23
|
&& mkdir -p /opt/sellable-agent/install-root /opt/sellable-agent/mcp-root \
|
|
24
24
|
&& npm install --prefix /opt/sellable-agent/install-root --omit=dev --ignore-scripts --no-audit --no-fund "${INSTALLER_PACKAGE}" \
|
|
25
25
|
&& npm install --prefix /opt/sellable-agent/mcp-root --omit=dev --ignore-scripts --no-audit --no-fund "${MCP_PACKAGE}" \
|
|
26
|
-
&& node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.
|
|
26
|
+
&& node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.433' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.760-wip.phase143.20260727100513') throw new Error('package identity rejected');" \
|
|
27
27
|
&& node --input-type=module -e "import { buildExternalRuntimeClosure } from '/opt/sellable-agent/install-root/node_modules/@sellable/install/lib/sellable-agent/external-runtime-builder.mjs'; const built = buildExternalRuntimeClosure({ mcpPackageRoot: '/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp', mcpNodeModulesRoot: '/opt/sellable-agent/mcp-root/node_modules', hermesSourceRoot: '/opt/hermes', ownerUid: 0, ownerGid: 0 }); if (!built.closureDigest) throw new Error('runtime closure rejected');" \
|
|
28
|
-
&& node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.
|
|
28
|
+
&& node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.433', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.760-wip.phase143.20260727100513', mcpIntegrity: process.argv[2] }; writeFileSync('/opt/sellable-agent/release.json', JSON.stringify(release) + '\\n', { mode: 0o444 }); chmodSync('/opt/sellable-agent/release.json', 0o444);" "${INSTALLER_INTEGRITY}" "${MCP_INTEGRITY}" \
|
|
29
29
|
&& npm cache clean --force
|
|
30
30
|
|
|
31
31
|
COPY entrypoint.sh /usr/local/bin/sellable-agent-container-entrypoint
|
package/container/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
This image is a dedicated Agent worker/runtime boundary beside an existing Hermes dashboard. It never replaces or reconfigures the dashboard container.
|
|
4
4
|
|
|
5
5
|
Build from this directory after
|
|
6
|
-
`@sellable/install@0.1.
|
|
6
|
+
`@sellable/install@0.1.433` is
|
|
7
7
|
published:
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
10
|
docker build --platform linux/amd64 \
|
|
11
11
|
--build-arg INSTALLER_INTEGRITY='sha512-…' \
|
|
12
|
-
--tag sellable-agent-host:0.1.
|
|
12
|
+
--tag sellable-agent-host:0.1.433 .
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Create a private `bootstrap/` directory owned by root with mode `0700`. It must contain `bootstrap.json`, `provider-auth`, and `slack-app`, each owned by root with mode `0600`. `bootstrap.json` contains only non-secret identities, hashes, package integrities, and the control-plane URL. The other two files contain the provider JSON and global Slack app token whose hashes are pinned by `bootstrap.json`.
|
|
@@ -3,9 +3,9 @@ FROM ${HERMES_IMAGE}
|
|
|
3
3
|
|
|
4
4
|
USER root
|
|
5
5
|
|
|
6
|
-
ARG MCP_PACKAGE=@sellable/mcp@0.1.
|
|
7
|
-
ARG MCP_INTEGRITY=sha512-
|
|
8
|
-
ARG INSTALLER_PACKAGE=@sellable/install@0.1.
|
|
6
|
+
ARG MCP_PACKAGE=@sellable/mcp@0.1.772
|
|
7
|
+
ARG MCP_INTEGRITY=sha512-9tSeLbH9U4Bg/XP0mriN1laMiU6MgNGnJMdXVxQTMvaZ7Mx84CCO7g1EPB7SLjX97XR8W37p1LbG7avl4K5QyA==
|
|
8
|
+
ARG INSTALLER_PACKAGE=@sellable/install@0.1.433
|
|
9
9
|
ARG HERMES_VERSION=0.19.0
|
|
10
10
|
ARG MCP_TRUST_ROOT_B64
|
|
11
11
|
ARG TIRITH_VERSION=0.3.3
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
FLY_CUSTOMER_MODEL_ID,
|
|
20
20
|
FLY_CUSTOMER_MODEL_PROVIDER,
|
|
21
21
|
FLY_CUSTOMER_MODEL_REASONING_EFFORT,
|
|
22
|
+
evaluateModelAuthReadback,
|
|
22
23
|
parseFlyCustomerModelCredential,
|
|
23
24
|
} from "../fly-customer-model.mjs";
|
|
24
25
|
import {
|
|
@@ -62,9 +63,9 @@ const RUNTIME_GENERATION = Number(
|
|
|
62
63
|
const BOOT_SESSION_ID = randomUUID();
|
|
63
64
|
const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.19.0";
|
|
64
65
|
const INSTALLER_PACKAGE =
|
|
65
|
-
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.
|
|
66
|
+
process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.433";
|
|
66
67
|
const MCP_PACKAGE =
|
|
67
|
-
process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.
|
|
68
|
+
process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.772";
|
|
68
69
|
|
|
69
70
|
const sha256 = (value) => createHash("sha256").update(value).digest("hex");
|
|
70
71
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -728,25 +729,27 @@ async function proveProvisionedApplication({
|
|
|
728
729
|
} catch {
|
|
729
730
|
modelAuthReadback = null;
|
|
730
731
|
}
|
|
732
|
+
const modelAuthVerdict = evaluateModelAuthReadback(modelAuthReadback);
|
|
733
|
+
if (modelAuth.status !== 0 || !modelAuthVerdict.accepted) {
|
|
734
|
+
// Name the failed invariant: a bare rejection sent the 2026-07-28 outage
|
|
735
|
+
// hunting the credential itself when the credential was valid and only its
|
|
736
|
+
// storage shape in the root auth store had changed.
|
|
737
|
+
throw new Error(
|
|
738
|
+
`customer_model_auth_readback_rejected:${
|
|
739
|
+
modelAuth.status !== 0
|
|
740
|
+
? "probe_failed"
|
|
741
|
+
: (modelAuthVerdict.rejection ?? "unknown")
|
|
742
|
+
}`
|
|
743
|
+
);
|
|
744
|
+
}
|
|
731
745
|
if (
|
|
732
746
|
hermesVersion.status !== 0 ||
|
|
733
747
|
mcpVersion.status !== 0 ||
|
|
734
|
-
modelAuth.status !== 0 ||
|
|
735
|
-
modelAuthReadback?.provider !== FLY_CUSTOMER_MODEL_PROVIDER ||
|
|
736
|
-
modelAuthReadback?.source !== "hermes-auth-store" ||
|
|
737
|
-
modelAuthReadback?.source_class !== "root_fallback" ||
|
|
738
|
-
modelAuthReadback?.auth_mode !== "chatgpt" ||
|
|
739
|
-
modelAuthReadback?.credential_present !== true ||
|
|
740
|
-
modelAuthReadback?.local_auth_entry_count !== 0 ||
|
|
741
748
|
/Lazy-installing|pip install|npm install/i.test(
|
|
742
749
|
`${hermesVersion.stdout}\n${hermesVersion.stderr}\n${mcpVersion.stdout}\n${mcpVersion.stderr}\n${modelAuth.stdout}\n${modelAuth.stderr}`
|
|
743
750
|
)
|
|
744
751
|
) {
|
|
745
|
-
throw new Error(
|
|
746
|
-
modelAuth.status !== 0 || !modelAuthReadback
|
|
747
|
-
? "customer_model_auth_readback_rejected"
|
|
748
|
-
: "customer_runtime_binary_rejected"
|
|
749
|
-
);
|
|
752
|
+
throw new Error("customer_runtime_binary_rejected");
|
|
750
753
|
}
|
|
751
754
|
return {
|
|
752
755
|
profileDigest,
|
|
@@ -14,6 +14,49 @@ const MODEL_TOKEN_KEYS = [
|
|
|
14
14
|
"id_token",
|
|
15
15
|
"refresh_token",
|
|
16
16
|
];
|
|
17
|
+
/**
|
|
18
|
+
* Credential sources that count as "resolved from this runtime's own root auth
|
|
19
|
+
* store". `hermes-auth-store` is the seeded singleton under `providers`;
|
|
20
|
+
* `credential_pool` is the pooled entry — which this module seeds itself (see
|
|
21
|
+
* `hermesRootAuthJson` below) and which `hermes auth add` also writes when an
|
|
22
|
+
* operator re-authenticates an expired Codex token. Both live in the same root
|
|
23
|
+
* auth.json, so neither weakens isolation: that guarantee is carried by
|
|
24
|
+
* `source_class === "root_fallback"` and `local_auth_entry_count === 0`, which
|
|
25
|
+
* together prove no profile-local auth.json is shadowing the root store.
|
|
26
|
+
*/
|
|
27
|
+
const TRUSTED_MODEL_AUTH_SOURCES = ["hermes-auth-store", "credential_pool"];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Decide whether the runtime's model-auth readback proves a usable, isolated
|
|
31
|
+
* Codex credential. Returns the first failed invariant so boot failures name
|
|
32
|
+
* the actual cause instead of a generic rejection.
|
|
33
|
+
*/
|
|
34
|
+
export function evaluateModelAuthReadback(readback) {
|
|
35
|
+
const reject = (rejection) => ({ accepted: false, rejection });
|
|
36
|
+
if (!readback || typeof readback !== "object" || Array.isArray(readback)) {
|
|
37
|
+
return reject("readback_unparsable");
|
|
38
|
+
}
|
|
39
|
+
if (readback.provider !== FLY_CUSTOMER_MODEL_PROVIDER) {
|
|
40
|
+
return reject("provider_mismatch");
|
|
41
|
+
}
|
|
42
|
+
if (readback.source_class !== "root_fallback") {
|
|
43
|
+
return reject("source_class_not_root_fallback");
|
|
44
|
+
}
|
|
45
|
+
if (readback.local_auth_entry_count !== 0) {
|
|
46
|
+
return reject("local_auth_entry_present");
|
|
47
|
+
}
|
|
48
|
+
if (!TRUSTED_MODEL_AUTH_SOURCES.includes(readback.source)) {
|
|
49
|
+
return reject("source_not_trusted");
|
|
50
|
+
}
|
|
51
|
+
if (readback.auth_mode !== "chatgpt") {
|
|
52
|
+
return reject("auth_mode_not_chatgpt");
|
|
53
|
+
}
|
|
54
|
+
if (readback.credential_present !== true) {
|
|
55
|
+
return reject("credential_absent");
|
|
56
|
+
}
|
|
57
|
+
return { accepted: true, rejection: null };
|
|
58
|
+
}
|
|
59
|
+
|
|
17
60
|
const exactKeys = (value, expected) =>
|
|
18
61
|
value &&
|
|
19
62
|
typeof value === "object" &&
|
|
@@ -38,7 +38,7 @@ import { installAgentHostServices } from "./service-installer.mjs";
|
|
|
38
38
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
|
|
39
39
|
const VERSION = "sellable-agent-host-bootstrap/v1";
|
|
40
40
|
const RECEIPT_VERSION = "sellable-agent-host-registration/v1";
|
|
41
|
-
const INSTALLER_PACKAGE = "@sellable/install@0.1.
|
|
41
|
+
const INSTALLER_PACKAGE = "@sellable/install@0.1.433";
|
|
42
42
|
const MCP_PACKAGE = "@sellable/mcp@0.1.760-wip.phase143.20260727100513";
|
|
43
43
|
const HERMES_VERSION = "0.18.0";
|
|
44
44
|
const SHA256 = /^[a-f0-9]{64}$/;
|
|
@@ -1513,7 +1513,7 @@ export function compileClaimToProfileDesired(activeClaim, config) {
|
|
|
1513
1513
|
]) ||
|
|
1514
1514
|
pinned.hermesCli !== "hermes" ||
|
|
1515
1515
|
pinned.hermesVersion !== "0.18.0" ||
|
|
1516
|
-
pinned.installerPackage !== "@sellable/install@0.1.
|
|
1516
|
+
pinned.installerPackage !== "@sellable/install@0.1.433" ||
|
|
1517
1517
|
pinned.mcpPackage !==
|
|
1518
1518
|
"@sellable/mcp@0.1.760-wip.phase143.20260727100513" ||
|
|
1519
1519
|
!Array.isArray(policy.toolInclude) ||
|
|
@@ -192,7 +192,7 @@ function validateDesired(desired) {
|
|
|
192
192
|
desired.serviceCredentialGeneration < 1 ||
|
|
193
193
|
desired.hermesCli !== "hermes" ||
|
|
194
194
|
desired.hermesVersion !== "0.18.0" ||
|
|
195
|
-
desired.installerPackage !== "@sellable/install@0.1.
|
|
195
|
+
desired.installerPackage !== "@sellable/install@0.1.433" ||
|
|
196
196
|
desired.mcpPackage !==
|
|
197
197
|
"@sellable/mcp@0.1.760-wip.phase143.20260727100513" ||
|
|
198
198
|
!Array.isArray(desired.toolInclude) ||
|
|
@@ -25,7 +25,7 @@ import { fileURLToPath } from "node:url";
|
|
|
25
25
|
import { deriveContainedProfileId } from "./profile-materializer.mjs";
|
|
26
26
|
|
|
27
27
|
export const PROVISIONING_ACTION = "PROVISION_HERMES_PROFILE";
|
|
28
|
-
export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.
|
|
28
|
+
export const PINNED_INSTALL_PACKAGE = "@sellable/install@0.1.433";
|
|
29
29
|
export const PINNED_MCP_PACKAGE =
|
|
30
30
|
"@sellable/mcp@0.1.760-wip.phase143.20260727100513";
|
|
31
31
|
|
|
@@ -612,7 +612,7 @@ function inspectProvisionedProfile({
|
|
|
612
612
|
!matchesReadback(manifest, request) ||
|
|
613
613
|
manifest.serviceCredentialReference !== serviceCredentialReference ||
|
|
614
614
|
manifest.installerPackage !== PINNED_INSTALL_PACKAGE ||
|
|
615
|
-
manifest.installerVersion !== "0.1.
|
|
615
|
+
manifest.installerVersion !== "0.1.433" ||
|
|
616
616
|
manifest.mcpPackage !== PINNED_MCP_PACKAGE ||
|
|
617
617
|
manifest.credentialKeyVersion !== credentialKeyVersion ||
|
|
618
618
|
!/^[a-f0-9]{16}$/.test(manifest.credentialFingerprint) ||
|
|
@@ -826,7 +826,7 @@ function successReceipt({
|
|
|
826
826
|
subject: `agent-profile:${observed.profileId}`,
|
|
827
827
|
cli: {
|
|
828
828
|
installPackage: PINNED_INSTALL_PACKAGE,
|
|
829
|
-
installVersion: "0.1.
|
|
829
|
+
installVersion: "0.1.433",
|
|
830
830
|
mcpPackage: PINNED_MCP_PACKAGE,
|
|
831
831
|
command: "hermes profile bootstrap",
|
|
832
832
|
},
|
|
@@ -874,7 +874,7 @@ function failure(code, stages, extra = {}, request = null) {
|
|
|
874
874
|
: "agent-profile:unbound",
|
|
875
875
|
cli: {
|
|
876
876
|
installPackage: PINNED_INSTALL_PACKAGE,
|
|
877
|
-
installVersion: "0.1.
|
|
877
|
+
installVersion: "0.1.433",
|
|
878
878
|
mcpPackage: PINNED_MCP_PACKAGE,
|
|
879
879
|
command: "hermes profile bootstrap",
|
|
880
880
|
},
|
package/package.json
CHANGED
|
@@ -3,9 +3,6 @@ name: refill-sends
|
|
|
3
3
|
description: Refill projected sends across a workspace or selected senders through the canonical fenced coordinator.
|
|
4
4
|
visibility: public
|
|
5
5
|
allowed-tools:
|
|
6
|
-
- mcp__sellable__refill_v3_sender_date_eligibility
|
|
7
|
-
- mcp__sellable__refill_v3_supply_assessment
|
|
8
|
-
- mcp__sellable__refill_v3_workspace_inventory
|
|
9
6
|
- mcp__sellable__refill_sends
|
|
10
7
|
- mcp__sellable__get_refill_target_plan
|
|
11
8
|
- mcp__sellable__get_scheduler_fill_capacity
|
|
@@ -33,79 +30,14 @@ Host commands:
|
|
|
33
30
|
- Claude Code: `/sellable:refill-sends`
|
|
34
31
|
- Codex: `$sellable:refill-sends`
|
|
35
32
|
|
|
36
|
-
## Refill v3 Calls 1–3a — progressive observation gate
|
|
37
|
-
|
|
38
|
-
Use this gate only when the operator explicitly requests `--observe-v3`,
|
|
39
|
-
explicitly asks to inspect or preview Refill V3 eligibility and supply without
|
|
40
|
-
refilling, or invokes a UAT request that names Calls 1–3a. An ordinary fill or
|
|
41
|
-
refill intent without `--observe-v3` skips this gate and continues at
|
|
42
|
-
`Entry and exact scope` below.
|
|
43
|
-
|
|
44
|
-
Do not combine `--observe-v3` with `--yolo`, scheduled execution, or legacy
|
|
45
|
-
execution in one invocation. If they are combined, stop with no tool call and
|
|
46
|
-
ask the operator to choose observation or execution.
|
|
47
|
-
|
|
48
|
-
1. Call `get_auth_status`. If Sellable authentication is not valid, run only
|
|
49
|
-
the returned login flow and recheck authentication.
|
|
50
|
-
2. Load
|
|
51
|
-
`get_subskill_asset({ subskillName: "refill-sends", assetPath: "core/flow.v3.json" })`
|
|
52
|
-
completely. Require `workflow:"refill-sends-v3"` and `version:3`. Follow
|
|
53
|
-
only the current state's `allowedTools`, `doNotLoad`, and transition.
|
|
54
|
-
3. Resolve the exact workspace by explicit ID, exact name, install mapping, or
|
|
55
|
-
an unambiguous accessible-workspace match using `get_active_workspace` and
|
|
56
|
-
`list_workspaces`. Never change the active workspace.
|
|
57
|
-
4. Call
|
|
58
|
-
`refill_v3_workspace_inventory({ workspaceId, detail: "concise" })` exactly
|
|
59
|
-
once.
|
|
60
|
-
5. For each globally eligible sender and requested sender-local date, call
|
|
61
|
-
`refill_v3_sender_date_eligibility` exactly once with the server-issued
|
|
62
|
-
`runId` and `fence`. Never call it for a globally ineligible sender.
|
|
63
|
-
6. Evaluate the invite and paid lane results independently. A typed blocker
|
|
64
|
-
terminates only that lane; it never suppresses another positively eligible
|
|
65
|
-
lane. For every positively eligible lane, call
|
|
66
|
-
`refill_v3_supply_assessment` exactly once for each campaign/lane tuple
|
|
67
|
-
issued by inventory. Pass the backend-applied quota as the assessment
|
|
68
|
-
bound; never invent or substitute a campaign, lane, sender, date, run
|
|
69
|
-
identity, or fence.
|
|
70
|
-
7. Render the complete inventory, sender/date eligibility, and supply result,
|
|
71
|
-
including every typed blocker. The observation run is terminal only after
|
|
72
|
-
every issued lane is terminal.
|
|
73
|
-
|
|
74
|
-
A sender whose LinkedIn account is connected but whose Sales Navigator status
|
|
75
|
-
is disconnected remains eligible for real non-Sales-Nav lanes. For Thomas or
|
|
76
|
-
any equivalent sender, the paid InMail lane must return
|
|
77
|
-
`sales_nav_disconnected` at eligibility and transition only that paid lane
|
|
78
|
-
directly to terminal `blocked`: do not call supply for the blocked paid lane,
|
|
79
|
-
refresh a provider, invoke Sales Navigator, or schedule or place anything.
|
|
80
|
-
Open InMail without a trusted classic route is likewise terminal only for that
|
|
81
|
-
open-InMail lane. Continue Thomas's positively eligible invite lane through its
|
|
82
|
-
issued campaign/lane tuples.
|
|
83
|
-
|
|
84
|
-
While `--observe-v3` is selected, do not load `refill-sends-workflow`, call
|
|
85
|
-
`get_refill_target_plan`, or call `refill_sends`. The host consumes
|
|
86
|
-
`--observe-v3`; never pass it to `refill_sends`. Calls 1–3a are backend-owned
|
|
87
|
-
observation calls; they may append their fenced decision ledger and Call 2 may
|
|
88
|
-
perform its bounded single-flight paid-credit cache refresh. They never approve
|
|
89
|
-
or enrich rows, acquire supply, change campaign state, invoke a Sales Navigator
|
|
90
|
-
provider action, schedule, place, or send. Between calls, retain the
|
|
91
|
-
server-issued `runId` and `fence`; never reconstruct downstream policy in the
|
|
92
|
-
host.
|
|
93
|
-
|
|
94
|
-
The sections below remain the default path for ordinary fill and refill
|
|
95
|
-
requests. `refill_sends` remains the only mutation execution owner; this
|
|
96
|
-
explicit observation gate does not introduce another mutation owner.
|
|
97
|
-
|
|
98
33
|
## Entry and exact scope
|
|
99
34
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
inclusive; `targetDate` is one sender-local scheduler-fillable date. Skip
|
|
107
|
-
no-send days and never extend beyond the requested date. Finish the full D1
|
|
108
|
-
reread before D2.
|
|
35
|
+
Accepted request fields are `--yolo`, `workspaceId`, `--sender`/`senderIds`/
|
|
36
|
+
`senderNames`, `actionTypes`, `--until`/`untilDate`, `--target-date`/
|
|
37
|
+
`targetDate`, and compatibility `horizonSendDays`. Omitted dates mean the
|
|
38
|
+
scheduler-forward 48-hour window. `untilDate` is sender-local and inclusive;
|
|
39
|
+
`targetDate` is one sender-local scheduler-fillable date. Skip no-send days and
|
|
40
|
+
never extend beyond the requested date. Finish the full D1 reread before D2.
|
|
109
41
|
|
|
110
42
|
```text
|
|
111
43
|
refill_sends({ yolo?: boolean, executionMode?: "manual" | "scheduled" | "yolo", requireWorkspace?: boolean, workspaceId?: string, senders?: string[], senderIds?: string[], senderNames?: string[], actionTypes?: ("send_invite" | "send_inmail_closed")[], horizonSendDays?: number, untilDate?: "YYYY-MM-DD", targetDate?: "YYYY-MM-DD", runHandle?: RefillRunHandleV1, targetConfig?: RefillTargetConfigV1, reportingContext?: RefillReportingContextV2, messageTemplateRevision?: MessageTemplateRevisionV1 })
|