@sellable/mcp 0.1.909 → 0.1.910

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.
@@ -1942,9 +1942,45 @@ export async function broadenSignalSearch(action, workspaceId) {
1942
1942
  name: campaign.name ?? "",
1943
1943
  },
1944
1944
  }, requestOptions);
1945
+ const estimates = estimateResponse.estimates ?? [];
1946
+ const estimatedPostIds = new Set(estimates
1947
+ .map((estimate) => stringValue(estimate.postId))
1948
+ .filter((postId) => Boolean(postId)));
1949
+ const reportedUnavailablePosts = (estimateResponse.unavailablePosts ?? []).flatMap((entry) => {
1950
+ const postId = stringValue(entry.postId);
1951
+ if (!postId)
1952
+ return [];
1953
+ return [
1954
+ {
1955
+ postId,
1956
+ reason: stringValue(entry.reason) ?? "evaluation_unavailable",
1957
+ },
1958
+ ];
1959
+ });
1960
+ const reportedUnavailablePostIds = new Set(reportedUnavailablePosts.map((entry) => entry.postId));
1961
+ const missingEstimatePosts = candidates.flatMap((candidate) => estimatedPostIds.has(candidate.postId) ||
1962
+ reportedUnavailablePostIds.has(candidate.postId)
1963
+ ? []
1964
+ : [{ postId: candidate.postId, reason: "missing_estimate" }]);
1965
+ const unavailablePosts = [
1966
+ ...reportedUnavailablePosts,
1967
+ ...missingEstimatePosts,
1968
+ ];
1969
+ if (unavailablePosts.length > 0) {
1970
+ return {
1971
+ candidatePostCount: candidates.length,
1972
+ engagerSum: 0,
1973
+ observedPassRate: 0,
1974
+ projectedYield: 0,
1975
+ floor: Math.min(SIGNAL_YIELD_FLOOR_CAP, Math.max(1, remainingPrepGap)),
1976
+ scrapePostIds: [],
1977
+ carriedPostIds: [],
1978
+ evaluationUnavailable: { posts: unavailablePosts },
1979
+ };
1980
+ }
1945
1981
  const sampled = selectRefillV3SignalPostsFromSamples({
1946
1982
  candidates,
1947
- estimates: estimateResponse.estimates ?? [],
1983
+ estimates,
1948
1984
  maxPosts: scrapeCap,
1949
1985
  });
1950
1986
  postYieldSamples = sampled.samples;
@@ -1970,6 +2006,34 @@ export async function broadenSignalSearch(action, workspaceId) {
1970
2006
  remainingPrepGap,
1971
2007
  maxPosts: maxPostsToScrape,
1972
2008
  });
2009
+ const evaluationUnavailable = "evaluationUnavailable" in yieldProjection
2010
+ ? recordValue(yieldProjection.evaluationUnavailable)
2011
+ : null;
2012
+ if (evaluationUnavailable) {
2013
+ const runScopedCleanup = await cleanupRunScopedDerivedTabs();
2014
+ return {
2015
+ status: "refused",
2016
+ refusalReason: "signal_post_icp_evaluation_unavailable: one or more candidate posts lacked a complete headline-ICP evaluation; no qualification or exhaustion receipt was recorded",
2017
+ result: {
2018
+ class: "source_retryable",
2019
+ code: "signal_post_icp_evaluation_unavailable",
2020
+ retryable: true,
2021
+ universeExhausted: false,
2022
+ campaignOfferId,
2023
+ keywordSource: effectiveKeywordSource,
2024
+ keywordsTried: searchKeywords,
2025
+ usedKeywords,
2026
+ searchedKeywords: negativeList,
2027
+ excludedPostIds,
2028
+ candidatePostCount: yieldProjection.candidatePostCount,
2029
+ unavailablePosts: Array.isArray(evaluationUnavailable.posts)
2030
+ ? evaluationUnavailable.posts
2031
+ : [],
2032
+ searchSummary,
2033
+ runScopedCleanup,
2034
+ },
2035
+ };
2036
+ }
1973
2037
  const noQualifyingV3Post = isRefillV3SinglePassAction(action) &&
1974
2038
  yieldProjection.scrapePostIds.length === 0;
1975
2039
  if (noQualifyingV3Post ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.909",
3
+ "version": "0.1.910",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",