@sellable/mcp 0.1.750 → 0.1.751

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.
@@ -2025,6 +2025,35 @@ function laneFrontierIsRubricTerminal(frontier) {
2025
2025
  const status = stringValue(diagnosis.status);
2026
2026
  return status === "zero_yield" || status === "low_yield";
2027
2027
  }
2028
+ // fix(112au): a lane can be receipt-proven spent WITHOUT the classifier having
2029
+ // labelled its stage `icp_or_rubric_rejection`. Dotwork's receipts carry
2030
+ // `retryable: false`, `status: "zero_yield"`, `activeCellCount: 0` and
2031
+ // `stage: "mixed_or_unknown"` (dominantReason legacy_progress_zero_yield), so
2032
+ // the lane stayed "convertible", kept its rows in the actionable census, and
2033
+ // the run terminaled `actionable_supply_not_queued` against supply it could
2034
+ // never convert — an owner-invariant breach caused by a MISSING stage label,
2035
+ // not by real actionable work.
2036
+ //
2037
+ // The substantive proof of exhaustion is: the preparation receipt is
2038
+ // NON-RETRYABLE, it yielded nothing, and there is no work still in flight.
2039
+ // The stage label is a classifier detail on top of that.
2040
+ //
2041
+ // activeCellCount === 0 is load-bearing: a lane with cells still processing is
2042
+ // mid-flight, not spent, and must keep its rows in the census so the
2043
+ // active-prep-job wait path wins instead of a false exhaustion terminal.
2044
+ function laneFrontierIsReceiptProvenSpent(frontier) {
2045
+ const frontierRecord = recordValue(frontier);
2046
+ const diagnosis = recordValue(frontierRecord?.failureDiagnosis);
2047
+ if (!diagnosis)
2048
+ return false;
2049
+ if (diagnosis.retryable !== false)
2050
+ return false;
2051
+ const status = stringValue(diagnosis.status);
2052
+ if (status !== "zero_yield" && status !== "low_yield")
2053
+ return false;
2054
+ const activeCells = numberValue(frontierRecord?.activeCellCount);
2055
+ return activeCells === 0;
2056
+ }
2028
2057
  // One frontier receipt describes one campaign table's lane, however many senders
2029
2058
  // share it. Fall back to sender identity only when the receipt did not name the
2030
2059
  // table it measured, so independent lanes still sum.
@@ -2099,7 +2128,8 @@ function workspaceActionableSupplyCensus(plan) {
2099
2128
  const stageCounts = recordValue(frontier?.stageCounts);
2100
2129
  const lane = workspaceLaneFrontier(planRecord, receipt, frontier, stageCounts);
2101
2130
  const laneKey = workspaceLaneFrontierKey(lane);
2102
- if (laneFrontierIsRubricTerminal(frontier)) {
2131
+ if (laneFrontierIsRubricTerminal(frontier) ||
2132
+ laneFrontierIsReceiptProvenSpent(frontier)) {
2103
2133
  mergeNonConvertibleLane(nonConvertibleByLane, laneKey, lane);
2104
2134
  continue;
2105
2135
  }
@@ -2185,7 +2215,11 @@ function workspaceGapBearingActionableSupply(plan) {
2185
2215
  const frontier = recordValue(receipt?.existingRowFrontier);
2186
2216
  const stageCounts = recordValue(frontier?.stageCounts);
2187
2217
  const lane = workspaceLaneFrontier(rec, receipt, frontier, stageCounts);
2188
- const rubricTerminal = laneFrontierIsRubricTerminal(frontier);
2218
+ // fix(112au): both convertibility splits must agree. This one feeds the
2219
+ // TERMINAL classifier, so a lane spent-by-receipt but unlabelled here would
2220
+ // still drive actionable_supply_not_queued.
2221
+ const rubricTerminal = laneFrontierIsRubricTerminal(frontier) ||
2222
+ laneFrontierIsReceiptProvenSpent(frontier);
2189
2223
  const laneActionable = rubricTerminal
2190
2224
  ? 0
2191
2225
  : lane.approval + lane.generate + lane.enrich + lane.rubric;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.750",
3
+ "version": "0.1.751",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",