@sellable/mcp 0.1.732 → 0.1.733
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.
|
@@ -1712,8 +1712,8 @@ export declare function executeRefillSendsCommand(input?: RefillSendsCommandInpu
|
|
|
1712
1712
|
readOnly: boolean;
|
|
1713
1713
|
ok: boolean;
|
|
1714
1714
|
status: "blocked";
|
|
1715
|
-
code: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued";
|
|
1716
|
-
blocker: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued";
|
|
1715
|
+
code: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued" | "source_supply_exhausted_at_rubric";
|
|
1716
|
+
blocker: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued" | "source_supply_exhausted_at_rubric";
|
|
1717
1717
|
note: string;
|
|
1718
1718
|
targetPlan: unknown;
|
|
1719
1719
|
exactTargetPlan: {} | null;
|
|
@@ -2931,8 +2931,8 @@ export declare function executeRefillSendsCommand(input?: RefillSendsCommandInpu
|
|
|
2931
2931
|
} | {
|
|
2932
2932
|
ok: boolean;
|
|
2933
2933
|
status: "blocked";
|
|
2934
|
-
code: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued";
|
|
2935
|
-
blocker: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued";
|
|
2934
|
+
code: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued" | "source_supply_exhausted_at_rubric";
|
|
2935
|
+
blocker: "workspace_exact_target_unavailable" | "workspace_exact_target_contract_missing" | "exact_target_config_unavailable" | "exact_target_config_mismatch" | "exact_target_projection_mismatch" | "new_campaign_required" | "actionable_supply_not_queued" | "source_supply_exhausted_at_rubric";
|
|
2936
2936
|
note: string;
|
|
2937
2937
|
targetPlan: unknown;
|
|
2938
2938
|
exactTargetPlan: {} | null;
|
|
@@ -454,7 +454,7 @@ function buildRefillSendsCommand(input) {
|
|
|
454
454
|
workflowAsset: {
|
|
455
455
|
subskillName: "refill-sends-workflow",
|
|
456
456
|
assetPath: "core/flow.v1.json",
|
|
457
|
-
expectedVersion: "v1.
|
|
457
|
+
expectedVersion: "v1.9",
|
|
458
458
|
},
|
|
459
459
|
yolo,
|
|
460
460
|
executionMode,
|
|
@@ -502,7 +502,7 @@ function buildRefillSendsCommand(input) {
|
|
|
502
502
|
},
|
|
503
503
|
firstOperationalSteps: [
|
|
504
504
|
'Load get_subskill_prompt({ subskillName: "refill-sends-workflow" }) before any product operation.',
|
|
505
|
-
'Load get_subskill_asset({ subskillName: "refill-sends-workflow", assetPath: "core/flow.v1.json" }) before any product operation; continue chunks until hasMore is false, parse JSON, and require exactly workflow:"refill-sends-workflow" and version:"v1.
|
|
505
|
+
'Load get_subskill_asset({ subskillName: "refill-sends-workflow", assetPath: "core/flow.v1.json" }) before any product operation; continue chunks until hasMore is false, parse JSON, and require exactly workflow:"refill-sends-workflow" and version:"v1.9". Report the verified version before D1. Any other or unverified version is workflow_version_mismatch and must stop before get_refill_target_plan or mutation.',
|
|
506
506
|
"A skill cannot create or invoke /goal by itself. If this refill is already running inside an active Codex goal, keep that goal open until every selected sender lane is horizon-filled by projected coverage (sent + scheduled), Christian explicitly stops/statuses the run, or a concrete non-scheduler blocker appears.",
|
|
507
507
|
`Call get_refill_target_plan({ intent: "${intent}"${workspaceId ? `, workspaceId: "${workspaceId}"` : ""}${input.campaignId ? `, campaignId: "${input.campaignId}"` : ""}${input.tableId ? `, tableId: "${input.tableId}"` : ""}${senderIds.length > 0 ? `, senderIds: ${JSON.stringify(senderIds)}` : ""}${senderNames.length > 0
|
|
508
508
|
? `, senderNames: ${JSON.stringify(senderNames)}`
|
|
@@ -1395,6 +1395,20 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
|
|
|
1395
1395
|
const prefilterBlockedTargets = blockedExactTargets.filter((blocked) => blocked.blocker !== "complete" &&
|
|
1396
1396
|
blocked.blocker !== "capped_by_scheduler");
|
|
1397
1397
|
const seenTargetKeys = new Set();
|
|
1398
|
+
// fix(112ak): every refusal is recorded so a non-empty-census terminal can
|
|
1399
|
+
// name the concrete per-lane blocker instead of reporting a bare dead end.
|
|
1400
|
+
const coordinatorExcludedEdges = [];
|
|
1401
|
+
const recordExcludedEdge = (candidate, blocked, stage) => {
|
|
1402
|
+
coordinatorExcludedEdges.push({
|
|
1403
|
+
campaignId: candidate.campaignId,
|
|
1404
|
+
tableId: candidate.tableId,
|
|
1405
|
+
senderIds: candidate.senderIds,
|
|
1406
|
+
actionTypes: candidate.actionTypes,
|
|
1407
|
+
actionKey: blocked?.actionKey ?? candidate.actionKey ?? null,
|
|
1408
|
+
blocker: blocked?.blocker ?? null,
|
|
1409
|
+
stage,
|
|
1410
|
+
});
|
|
1411
|
+
};
|
|
1398
1412
|
const targetCandidates = actionTargets.filter((candidate) => {
|
|
1399
1413
|
const key = workspaceExactTargetKey(candidate);
|
|
1400
1414
|
if (seenTargetKeys.has(key))
|
|
@@ -1424,6 +1438,7 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
|
|
|
1424
1438
|
workspaceActionFamily(candidate.actionKey) === "run_scheduler_sweep") {
|
|
1425
1439
|
return false;
|
|
1426
1440
|
}
|
|
1441
|
+
recordExcludedEdge(candidate, blocked, "prefilter");
|
|
1427
1442
|
return true;
|
|
1428
1443
|
}));
|
|
1429
1444
|
});
|
|
@@ -1497,7 +1512,7 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
|
|
|
1497
1512
|
blockedExactTargets.length > 0
|
|
1498
1513
|
? "The fresh workspace queue did not expose another exact campaign/table edge after excluding the structurally exhausted target. No refill run or mutation was started."
|
|
1499
1514
|
: "The fresh workspace queue did not expose one exact campaign/table edge at globalActionQueue[0]. No refill run or mutation was started.") +
|
|
1500
|
-
workspaceTypedBlockersNote(workspacePlan)),
|
|
1515
|
+
workspaceTypedBlockersNote(workspacePlan), coordinatorExcludedEdges),
|
|
1501
1516
|
workspacePlan,
|
|
1502
1517
|
};
|
|
1503
1518
|
}
|
|
@@ -1668,6 +1683,7 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
|
|
|
1668
1683
|
blocked.blocker === "loaded_awaiting_scheduler") {
|
|
1669
1684
|
return false;
|
|
1670
1685
|
}
|
|
1686
|
+
recordExcludedEdge(exactSelectedTarget, blocked, "post_rebind");
|
|
1671
1687
|
return true;
|
|
1672
1688
|
})) {
|
|
1673
1689
|
continue;
|
|
@@ -1791,7 +1807,7 @@ async function selectWorkspaceExactTarget(input, workspacePlanOverride, options
|
|
|
1791
1807
|
...classifyWorkspaceUnavailableTerminal(workspacePlan, (workspaceCoverage.remainingReadyOrProjectedGap !== 0
|
|
1792
1808
|
? `The fresh workspace plan still has ${workspaceCoverage.remainingReadyOrProjectedGap ?? "an unknown number of"} rows to prepare, but its executable exact-target candidates were all complete or scheduler-loaded. Refusing a false loaded_awaiting_scheduler terminal; the planner must expose the remaining actionable lane or a concrete blocker.`
|
|
1793
1809
|
: `The fresh workspace queue remained incomplete, but all ${completedExactTargetCount} exposed exact targets were already complete and no active preparation or import work was pending. No identical refill fence was reopened.`) +
|
|
1794
|
-
workspaceTypedBlockersNote(workspacePlan)),
|
|
1810
|
+
workspaceTypedBlockersNote(workspacePlan), coordinatorExcludedEdges),
|
|
1795
1811
|
workspacePlan,
|
|
1796
1812
|
};
|
|
1797
1813
|
}
|
|
@@ -1832,43 +1848,109 @@ function yoloCoverage(plan) {
|
|
|
1832
1848
|
targetShapeRevision: stringValue(recordValue(plan)?.targetShapeRevision),
|
|
1833
1849
|
};
|
|
1834
1850
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1851
|
+
function laneFrontierIsRubricTerminal(frontier) {
|
|
1852
|
+
const diagnosis = recordValue(recordValue(frontier)?.failureDiagnosis);
|
|
1853
|
+
if (!diagnosis)
|
|
1854
|
+
return false;
|
|
1855
|
+
if (diagnosis.retryable !== false)
|
|
1856
|
+
return false;
|
|
1857
|
+
if (stringValue(diagnosis.stage) !== "icp_or_rubric_rejection")
|
|
1858
|
+
return false;
|
|
1859
|
+
const status = stringValue(diagnosis.status);
|
|
1860
|
+
return status === "zero_yield" || status === "low_yield";
|
|
1861
|
+
}
|
|
1862
|
+
// One frontier receipt describes one campaign table's lane, however many senders
|
|
1863
|
+
// share it. Fall back to sender identity only when the receipt did not name the
|
|
1864
|
+
// table it measured, so independent lanes still sum.
|
|
1865
|
+
function workspaceLaneFrontierKey(lane) {
|
|
1866
|
+
return lane.campaignId && lane.tableId
|
|
1867
|
+
? `table:${lane.campaignId}:${lane.tableId}:${lane.actionType ?? ""}`
|
|
1868
|
+
: `sender:${lane.senderId ?? ""}:${lane.actionType ?? ""}`;
|
|
1869
|
+
}
|
|
1870
|
+
function workspaceLaneFrontier(planRecord, receipt, frontier, stageCounts) {
|
|
1871
|
+
const senderId = stringValue(planRecord?.senderId) ?? stringValue(receipt?.senderId);
|
|
1872
|
+
const diagnosis = recordValue(frontier?.failureDiagnosis);
|
|
1873
|
+
const evidence = recordValue(diagnosis?.evidence);
|
|
1874
|
+
const rejectionCounts = recordValue(evidence?.counts);
|
|
1875
|
+
return {
|
|
1876
|
+
senderId,
|
|
1877
|
+
senderIds: senderId ? [senderId] : [],
|
|
1878
|
+
actionType: stringValue(planRecord?.actionType) ?? stringValue(receipt?.actionType),
|
|
1879
|
+
campaignId: stringValue(receipt?.selectedCampaignId),
|
|
1880
|
+
tableId: stringValue(receipt?.selectedTableId),
|
|
1881
|
+
approval: Math.max(numberValue(receipt?.approvalCandidates) ?? 0, numberValue(stageCounts?.needsApproval) ?? 0),
|
|
1882
|
+
generate: numberValue(stageCounts?.needsGenerate) ?? 0,
|
|
1883
|
+
enrich: numberValue(stageCounts?.needsEnrich) ?? 0,
|
|
1884
|
+
rubric: numberValue(stageCounts?.needsRubric) ?? 0,
|
|
1885
|
+
hasMoreFrontierRows: frontier?.hasMoreFrontierRows === true,
|
|
1886
|
+
checkedRows: numberValue(evidence?.checkedRows) ?? null,
|
|
1887
|
+
rubricRejections: numberValue(rejectionCounts?.rubric_rejection) ?? null,
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
// Keep the deepest observation of a shared table lane so a terminal quotes the
|
|
1891
|
+
// scan that actually proved exhaustion, not the shallowest — but carry EVERY
|
|
1892
|
+
// sender the lane covers so no enrolled sender is left unexplained.
|
|
1893
|
+
function mergeNonConvertibleLane(lanes, laneKey, lane) {
|
|
1894
|
+
const seen = lanes.get(laneKey);
|
|
1895
|
+
if (!seen) {
|
|
1896
|
+
lanes.set(laneKey, lane);
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
const senderIds = [...new Set([...seen.senderIds, ...lane.senderIds])];
|
|
1900
|
+
if ((lane.checkedRows ?? 0) > (seen.checkedRows ?? 0)) {
|
|
1901
|
+
lanes.set(laneKey, { ...lane, senderIds });
|
|
1902
|
+
}
|
|
1903
|
+
else {
|
|
1904
|
+
seen.senderIds = senderIds;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
// Same table lane observed twice: keep the richest observation rather than
|
|
1908
|
+
// summing duplicates of one frontier.
|
|
1909
|
+
function mergeConvertibleLane(lanes, laneKey, lane) {
|
|
1910
|
+
const existing = lanes.get(laneKey);
|
|
1911
|
+
if (!existing) {
|
|
1912
|
+
lanes.set(laneKey, lane);
|
|
1913
|
+
return;
|
|
1914
|
+
}
|
|
1915
|
+
existing.approval = Math.max(existing.approval, lane.approval);
|
|
1916
|
+
existing.generate = Math.max(existing.generate, lane.generate);
|
|
1917
|
+
existing.enrich = Math.max(existing.enrich, lane.enrich);
|
|
1918
|
+
existing.rubric = Math.max(existing.rubric, lane.rubric);
|
|
1919
|
+
existing.hasMoreFrontierRows =
|
|
1920
|
+
existing.hasMoreFrontierRows || lane.hasMoreFrontierRows;
|
|
1921
|
+
existing.senderIds = [...new Set([...existing.senderIds, ...lane.senderIds])];
|
|
1922
|
+
}
|
|
1845
1923
|
function workspaceActionableSupplyCensus(plan) {
|
|
1846
1924
|
const target = yoloTarget(plan);
|
|
1847
1925
|
const senderPlansRaw = target?.senderPlans;
|
|
1848
1926
|
const senderPlans = Array.isArray(senderPlansRaw) ? senderPlansRaw : [];
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
let enrichFrontier = 0;
|
|
1852
|
-
let rubricFrontier = 0;
|
|
1853
|
-
let frontierHasMoreRows = false;
|
|
1927
|
+
const convertibleByLane = new Map();
|
|
1928
|
+
const nonConvertibleByLane = new Map();
|
|
1854
1929
|
for (const senderPlan of senderPlans) {
|
|
1855
|
-
const
|
|
1930
|
+
const planRecord = recordValue(senderPlan);
|
|
1931
|
+
const receipt = recordValue(planRecord?.refillReceipt);
|
|
1856
1932
|
const frontier = recordValue(receipt?.existingRowFrontier);
|
|
1857
1933
|
const stageCounts = recordValue(frontier?.stageCounts);
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1934
|
+
const lane = workspaceLaneFrontier(planRecord, receipt, frontier, stageCounts);
|
|
1935
|
+
const laneKey = workspaceLaneFrontierKey(lane);
|
|
1936
|
+
if (laneFrontierIsRubricTerminal(frontier)) {
|
|
1937
|
+
mergeNonConvertibleLane(nonConvertibleByLane, laneKey, lane);
|
|
1938
|
+
continue;
|
|
1939
|
+
}
|
|
1940
|
+
mergeConvertibleLane(convertibleByLane, laneKey, lane);
|
|
1864
1941
|
}
|
|
1942
|
+
const convertibleLanes = [...convertibleByLane.values()];
|
|
1943
|
+
const nonConvertibleLanes = [...nonConvertibleByLane.values()];
|
|
1944
|
+
const sum = (pick) => convertibleLanes.reduce((total, lane) => total + pick(lane), 0);
|
|
1865
1945
|
return {
|
|
1866
|
-
approvalFrontier,
|
|
1867
|
-
generateFrontier,
|
|
1868
|
-
enrichFrontier,
|
|
1869
|
-
rubricFrontier,
|
|
1870
|
-
frontierHasMoreRows,
|
|
1946
|
+
approvalFrontier: sum((lane) => lane.approval),
|
|
1947
|
+
generateFrontier: sum((lane) => lane.generate),
|
|
1948
|
+
enrichFrontier: sum((lane) => lane.enrich),
|
|
1949
|
+
rubricFrontier: sum((lane) => lane.rubric),
|
|
1950
|
+
frontierHasMoreRows: convertibleLanes.some((lane) => lane.hasMoreFrontierRows),
|
|
1871
1951
|
senderPlanCount: senderPlans.length,
|
|
1952
|
+
convertibleLanes,
|
|
1953
|
+
nonConvertibleLanes,
|
|
1872
1954
|
};
|
|
1873
1955
|
}
|
|
1874
1956
|
// fix(112ak, OWNER closing invariant): the workspace terminal classifier must
|
|
@@ -1897,6 +1979,34 @@ function workspaceGapBearingActionableSupply(plan) {
|
|
|
1897
1979
|
let gapSenderCount = 0;
|
|
1898
1980
|
let readySurplusGapSenders = 0;
|
|
1899
1981
|
let opaqueGapSenders = 0;
|
|
1982
|
+
// fix(112ak, supply validation + de-duplication): the gap-bearing census is the
|
|
1983
|
+
// authority behind the OWNER closing invariant, so it must count CONVERTIBLE
|
|
1984
|
+
// rows ONCE. Two live inflations broke that on the 2026-07-29 sweep.
|
|
1985
|
+
//
|
|
1986
|
+
// 1. Double counting. Every sender enrolled on a shared campaign reports the
|
|
1987
|
+
// SAME table frontier: sellable's "681 enrich" was one 68-row frontier on
|
|
1988
|
+
// campaign cmrcd4x4a counted 10x (nine send_invite lanes plus one
|
|
1989
|
+
// send_inmail_closed lane on the same table). Sums are now keyed by the
|
|
1990
|
+
// campaign/table/lane the receipt was actually measured on; plans without
|
|
1991
|
+
// table identity keep per-sender identity so independent lanes still sum.
|
|
1992
|
+
//
|
|
1993
|
+
// 2. Non-convertible rows counted as supply. Clover's lanes reported
|
|
1994
|
+
// stageCounts of ~0 with hasMoreFrontierRows true while their own receipts
|
|
1995
|
+
// carried failureDiagnosis {stage:"icp_or_rubric_rejection",
|
|
1996
|
+
// retryable:false} over the 4,993 rubric-rejected rows behind the scan
|
|
1997
|
+
// window. hasMoreFrontierRows is a SCAN-WINDOW flag, not evidence that
|
|
1998
|
+
// anything behind it can convert. Such a lane no longer inflates the
|
|
1999
|
+
// census; it is carried as non-convertible (with every sender it covers)
|
|
2000
|
+
// so the terminal can name a truthful exhaustion instead of the defect
|
|
2001
|
+
// class. Its bucket still counts honestly below, so a rubric-terminal lane
|
|
2002
|
+
// with no ready rows reads opaque and never fakes a loaded terminal.
|
|
2003
|
+
//
|
|
2004
|
+
// Only the receipt's own non-retryable rubric verdict disqualifies a lane.
|
|
2005
|
+
// Retryable diagnoses (sellable's dependency_blocked/retryable:true) and other
|
|
2006
|
+
// stages (Dotwork's approval_blocked over a real needsApproval row) stay
|
|
2007
|
+
// convertible, so the 112af-c/112ai masked-supply admission is untouched.
|
|
2008
|
+
const convertibleByLane = new Map();
|
|
2009
|
+
const nonConvertibleByLane = new Map();
|
|
1900
2010
|
for (const senderPlan of senderPlans) {
|
|
1901
2011
|
const rec = recordValue(senderPlan);
|
|
1902
2012
|
const gap = numberValue(rec?.remainingProjectedGap);
|
|
@@ -1908,26 +2018,37 @@ function workspaceGapBearingActionableSupply(plan) {
|
|
|
1908
2018
|
const receipt = recordValue(rec?.refillReceipt);
|
|
1909
2019
|
const frontier = recordValue(receipt?.existingRowFrontier);
|
|
1910
2020
|
const stageCounts = recordValue(frontier?.stageCounts);
|
|
1911
|
-
const
|
|
1912
|
-
const
|
|
1913
|
-
const
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
const
|
|
2021
|
+
const lane = workspaceLaneFrontier(rec, receipt, frontier, stageCounts);
|
|
2022
|
+
const rubricTerminal = laneFrontierIsRubricTerminal(frontier);
|
|
2023
|
+
const laneActionable = rubricTerminal
|
|
2024
|
+
? 0
|
|
2025
|
+
: lane.approval + lane.generate + lane.enrich + lane.rubric;
|
|
2026
|
+
const laneFrontierFlag = rubricTerminal ? false : lane.hasMoreFrontierRows;
|
|
1917
2027
|
const laneReady = numberValue(stageCounts?.ready) ?? 0;
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
2028
|
+
const laneKey = workspaceLaneFrontierKey(lane);
|
|
2029
|
+
if (rubricTerminal) {
|
|
2030
|
+
mergeNonConvertibleLane(nonConvertibleByLane, laneKey, lane);
|
|
2031
|
+
}
|
|
2032
|
+
else {
|
|
2033
|
+
mergeConvertibleLane(convertibleByLane, laneKey, lane);
|
|
2034
|
+
}
|
|
2035
|
+
if (laneFrontierFlag)
|
|
1923
2036
|
frontierHasMoreRows = true;
|
|
1924
|
-
if (laneActionable === 0 && !
|
|
2037
|
+
if (laneActionable === 0 && !laneFrontierFlag) {
|
|
1925
2038
|
if (laneReady > 0)
|
|
1926
2039
|
readySurplusGapSenders += 1;
|
|
1927
2040
|
else
|
|
1928
2041
|
opaqueGapSenders += 1;
|
|
1929
2042
|
}
|
|
1930
2043
|
}
|
|
2044
|
+
const convertibleLanes = [...convertibleByLane.values()];
|
|
2045
|
+
const nonConvertibleLanes = [...nonConvertibleByLane.values()];
|
|
2046
|
+
for (const lane of convertibleLanes) {
|
|
2047
|
+
approvalFrontier += lane.approval;
|
|
2048
|
+
generateFrontier += lane.generate;
|
|
2049
|
+
enrichFrontier += lane.enrich;
|
|
2050
|
+
rubricFrontier += lane.rubric;
|
|
2051
|
+
}
|
|
1931
2052
|
const actionableRows = approvalFrontier + generateFrontier + enrichFrontier + rubricFrontier;
|
|
1932
2053
|
return {
|
|
1933
2054
|
approvalFrontier,
|
|
@@ -1939,6 +2060,8 @@ function workspaceGapBearingActionableSupply(plan) {
|
|
|
1939
2060
|
gapSenderCount,
|
|
1940
2061
|
readySurplusGapSenders,
|
|
1941
2062
|
opaqueGapSenders,
|
|
2063
|
+
convertibleLanes,
|
|
2064
|
+
nonConvertibleLanes,
|
|
1942
2065
|
};
|
|
1943
2066
|
}
|
|
1944
2067
|
// fix(112ak): when the workspace gap is owed entirely by gap-bearing lanes whose
|
|
@@ -1968,23 +2091,106 @@ function readySurplusLoadedSelection(workspacePlan) {
|
|
|
1968
2091
|
}
|
|
1969
2092
|
return null;
|
|
1970
2093
|
}
|
|
1971
|
-
|
|
2094
|
+
// fix(112ak): a receipt-proven rubric-terminal frontier is a truthful source
|
|
2095
|
+
// exhaustion, so name it per lane instead of leaving the terminal generic.
|
|
2096
|
+
function workspaceRubricExhaustionNote(lanes) {
|
|
2097
|
+
const parts = lanes.slice(0, 12).map((lane) => {
|
|
2098
|
+
const scope = [
|
|
2099
|
+
lane.campaignId ?? lane.senderId,
|
|
2100
|
+
lane.actionType,
|
|
2101
|
+
lane.senderIds.length > 0 ? `${lane.senderIds.length} sender(s)` : null,
|
|
2102
|
+
]
|
|
2103
|
+
.filter((part) => Boolean(part))
|
|
2104
|
+
.join(":");
|
|
2105
|
+
const detail = [
|
|
2106
|
+
typeof lane.checkedRows === "number"
|
|
2107
|
+
? `${lane.checkedRows} checked`
|
|
2108
|
+
: null,
|
|
2109
|
+
typeof lane.rubricRejections === "number"
|
|
2110
|
+
? `${lane.rubricRejections} rubric-rejected`
|
|
2111
|
+
: null,
|
|
2112
|
+
]
|
|
2113
|
+
.filter((part) => Boolean(part))
|
|
2114
|
+
.join(", ");
|
|
2115
|
+
return detail
|
|
2116
|
+
? `${scope || "lane"} (${detail})`
|
|
2117
|
+
: scope || "unnamed sender lane";
|
|
2118
|
+
});
|
|
2119
|
+
if (parts.length === 0)
|
|
2120
|
+
return "";
|
|
2121
|
+
const overflow = lanes.length - parts.length;
|
|
2122
|
+
return ` Per-lane exhaustion evidence: ${parts.join("; ")}${overflow > 0 ? `; +${overflow} more lanes` : ""}.`;
|
|
2123
|
+
}
|
|
2124
|
+
function coordinatorExcludedEdgesNote(edges) {
|
|
2125
|
+
if (edges.length === 0)
|
|
2126
|
+
return "";
|
|
2127
|
+
const seen = new Set();
|
|
2128
|
+
const parts = [];
|
|
2129
|
+
for (const edge of edges) {
|
|
2130
|
+
const key = `${edge.campaignId}:${edge.tableId}:${edge.actionTypes.join(",")}:${edge.actionKey ?? ""}:${edge.blocker ?? ""}`;
|
|
2131
|
+
if (seen.has(key))
|
|
2132
|
+
continue;
|
|
2133
|
+
seen.add(key);
|
|
2134
|
+
const lane = edge.actionTypes.join("/") || "lane";
|
|
2135
|
+
const senders = edge.senderIds.length > 0
|
|
2136
|
+
? `${edge.senderIds.length} sender(s)`
|
|
2137
|
+
: "no named sender";
|
|
2138
|
+
parts.push(`${edge.campaignId}:${lane} (${senders}) refused as ${edge.blocker ?? "already-decided"}${edge.actionKey ? ` on ${edge.actionKey}` : ""} at ${edge.stage}`);
|
|
2139
|
+
if (parts.length >= 8)
|
|
2140
|
+
break;
|
|
2141
|
+
}
|
|
2142
|
+
const overflow = edges.length - parts.length;
|
|
2143
|
+
return ` Exact edges this run refused: ${parts.join("; ")}${overflow > 0 ? `; +${overflow} more` : ""}.`;
|
|
2144
|
+
}
|
|
2145
|
+
function classifyWorkspaceUnavailableTerminal(plan, contextNote, excludedEdges = []) {
|
|
1972
2146
|
// fix(112ak): gap-gate the actionable_supply signal — only supply behind a
|
|
1973
2147
|
// gap-bearing lane proves the planner failed to expose actionable work. A
|
|
1974
2148
|
// covered sender's surplus frontier/stage rows do NOT justify the defect class.
|
|
1975
2149
|
const census = workspaceGapBearingActionableSupply(plan);
|
|
1976
2150
|
const actionableRows = census.actionableRows;
|
|
1977
2151
|
if (actionableRows > 0 || census.frontierHasMoreRows) {
|
|
2152
|
+
// fix(112ak, OWNER closing invariant): a non-empty census may never end as
|
|
2153
|
+
// a bare defect terminal — the coordinator must dispatch an edge or NAME
|
|
2154
|
+
// the concrete per-lane blocker. Every edge this run refused is already
|
|
2155
|
+
// recorded with its sender/lane/actionKey and the receipt that refused it,
|
|
2156
|
+
// so surface that instead of claiming no edge was exposed. On the live
|
|
2157
|
+
// 2026-07-29 sellable run the planner DID expose a prepare edge; the
|
|
2158
|
+
// coordinator dropped it because the exact preflight re-issued an
|
|
2159
|
+
// actionKey already proven exact_action_complete, then reported "no
|
|
2160
|
+
// executable exact edge" — true only of the coordinator, not the planner.
|
|
2161
|
+
const exclusionNote = coordinatorExcludedEdgesNote(excludedEdges);
|
|
1978
2162
|
return {
|
|
1979
2163
|
code: "actionable_supply_not_queued",
|
|
1980
2164
|
note: `Actionable existing-row supply remains (${census.approvalFrontier} approval, ` +
|
|
1981
2165
|
`${census.generateFrontier} generate, ${census.enrichFrontier} enrich, ` +
|
|
1982
2166
|
`${census.rubricFrontier} rubric candidates across gap-bearing sender lanes` +
|
|
1983
2167
|
`${census.frontierHasMoreRows ? ", plus unprocessed frontier rows" : ""}) ` +
|
|
1984
|
-
|
|
2168
|
+
`${exclusionNote
|
|
2169
|
+
? "and every exact edge the planner exposed for it was refused by this run."
|
|
2170
|
+
: "but the fresh workspace queue exposed no executable exact edge for it."} ` +
|
|
1985
2171
|
"This is retryable: re-run refill_sends with a fresh command; if it repeats, " +
|
|
1986
2172
|
"report it as a planner-exposure defect. " +
|
|
1987
|
-
contextNote
|
|
2173
|
+
contextNote +
|
|
2174
|
+
exclusionNote,
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
// fix(112ak): the convertible census is empty and the only frontier left is
|
|
2178
|
+
// receipt-proven rubric-terminal (Clover 2026-07-29: nine lanes, all
|
|
2179
|
+
// non-retryable icp_or_rubric_rejection, 4,993 rubric-rejected rows behind
|
|
2180
|
+
// the scan window). That is a truthful source exhaustion, not the
|
|
2181
|
+
// planner-exposure defect class and not a generic dead end.
|
|
2182
|
+
if (census.nonConvertibleLanes.length > 0) {
|
|
2183
|
+
return {
|
|
2184
|
+
code: "source_supply_exhausted_at_rubric",
|
|
2185
|
+
note: `Every remaining existing-row frontier is receipt-proven exhausted at the ICP/rubric ` +
|
|
2186
|
+
`stage across ${census.nonConvertibleLanes.length} campaign/table lane(s): the preparation ` +
|
|
2187
|
+
"receipts report a non-retryable zero/low-yield rubric rejection, so the rows behind " +
|
|
2188
|
+
"the scan window cannot convert into sends. No campaign was created and no source was " +
|
|
2189
|
+
"expanded — widening the rubric or adding fresh source rows is the only remaining fill " +
|
|
2190
|
+
"path; surface this to the user. " +
|
|
2191
|
+
contextNote +
|
|
2192
|
+
workspaceRubricExhaustionNote(census.nonConvertibleLanes) +
|
|
2193
|
+
coordinatorExcludedEdgesNote(excludedEdges),
|
|
1988
2194
|
};
|
|
1989
2195
|
}
|
|
1990
2196
|
const coverage = yoloCoverage(plan);
|
package/package.json
CHANGED
|
@@ -75,7 +75,7 @@ get_subskill_asset({ subskillName: "refill-sends-workflow", assetPath: "core/flo
|
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
Continue chunks until `hasMore:false`; require
|
|
78
|
-
exactly `workflow:"refill-sends-workflow"` and `version:"v1.
|
|
78
|
+
exactly `workflow:"refill-sends-workflow"` and `version:"v1.9"`, then report
|
|
79
79
|
that verified version before D1. Any other or unverified version is
|
|
80
80
|
`workflow_version_mismatch`: stop before `get_refill_target_plan` or mutation.
|
|
81
81
|
Route intent is immutable:
|
|
@@ -484,9 +484,13 @@ flowchart TD
|
|
|
484
484
|
|
|
485
485
|
One scheduler-loaded exact lane is not a workspace terminal: skip it and
|
|
486
486
|
continue other planner-ranked lanes. Do not keep polling after the coordinator
|
|
487
|
-
returns workspace `loaded_awaiting_scheduler
|
|
488
|
-
remaining exact target is complete or scheduler-owned and
|
|
489
|
-
`remainingReadyOrProjectedGap` is zero
|
|
487
|
+
returns workspace `loaded_awaiting_scheduler`. That terminal is admissible by
|
|
488
|
+
either path: every remaining exact target is complete or scheduler-owned and
|
|
489
|
+
workspace `remainingReadyOrProjectedGap` is zero, OR every gap-bearing sender
|
|
490
|
+
lane is already prepared and its residue is `ready_to_schedule` surplus, so the
|
|
491
|
+
remaining gap is scheduler/pacing-bound rather than unexposed supply — on that
|
|
492
|
+
second path `remainingReadyOrProjectedGap` is not necessarily zero. Neither path
|
|
493
|
+
means unexposed actionable supply, and neither is permission for a host-owned
|
|
490
494
|
loop. The sole refill-ladder expansion
|
|
491
495
|
that asks the user in `--yolo` is `new_campaign_required`; refill itself never
|
|
492
496
|
creates that campaign. `new_campaign_required` is also the truthful terminal
|
|
@@ -497,7 +501,17 @@ remaining gap and ask the user; a future handler may automate the creation. A
|
|
|
497
501
|
(approval/generate/enrich/rubric or unprocessed frontier rows) still exist but
|
|
498
502
|
no executable exact edge surfaced: retry once with a fresh command, and if it
|
|
499
503
|
repeats report it as a planner-exposure defect instead of treating the
|
|
500
|
-
workspace as exhausted.
|
|
504
|
+
workspace as exhausted. That census counts CONVERTIBLE rows only, de-duplicated
|
|
505
|
+
per campaign/table lane — a frontier whose own preparation receipt carries a
|
|
506
|
+
non-retryable `icp_or_rubric_rejection` diagnosis is proven unable to convert,
|
|
507
|
+
so it never inflates the census. When such receipts are all that remain, the
|
|
508
|
+
terminal is `source_supply_exhausted_at_rubric`: a truthful source exhaustion,
|
|
509
|
+
not a defect and not retryable. Report the per-lane evidence from the note and
|
|
510
|
+
tell the user that widening the rubric or adding fresh source rows is the only
|
|
511
|
+
remaining fill path. Whenever a terminal reports a non-empty census, it also
|
|
512
|
+
names every exact edge the run refused (`Exact edges this run refused: ...`) —
|
|
513
|
+
surface those named blockers rather than describing the workspace as having no
|
|
514
|
+
available work.
|
|
501
515
|
|
|
502
516
|
## Non-negotiable authority and proof
|
|
503
517
|
|
|
@@ -24,7 +24,7 @@ In `--yolo`, the coordinator may
|
|
|
24
24
|
perform every fresh planner-ranked safe transition among existing campaigns,
|
|
25
25
|
lanes, and source families. It may not create a new campaign.
|
|
26
26
|
|
|
27
|
-
The host must load the entire asset and verify exactly `version:"v1.
|
|
27
|
+
The host must load the entire asset and verify exactly `version:"v1.9"` before
|
|
28
28
|
D1. It reports that verified version explicitly. A different or unverified
|
|
29
29
|
version is `workflow_version_mismatch` and stops before planner or mutation.
|
|
30
30
|
|
|
@@ -32,7 +32,7 @@ version is `workflow_version_mismatch` and stops before planner or mutation.
|
|
|
32
32
|
|
|
33
33
|
```mermaid
|
|
34
34
|
flowchart TD
|
|
35
|
-
A["Receive exact workspace, sender/action selectors, and date envelope"] --> ASSET["Verify complete flow.v1.json, workflow refill-sends-workflow, exact version v1.
|
|
35
|
+
A["Receive exact workspace, sender/action selectors, and date envelope"] --> ASSET["Verify complete flow.v1.json, workflow refill-sends-workflow, exact version v1.9"]
|
|
36
36
|
ASSET --> D1["Call get_refill_target_plan read-only with immutable route intent"]
|
|
37
37
|
D1 --> RENDER["Render sender/campaign waterfall, coverage ledger, bounded side effects, forbidden actions, and stop condition"]
|
|
38
38
|
RENDER --> D2["Call refill_sends with workspaceCoordinator true and displayed revision/action pins"]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "v1.
|
|
2
|
+
"version": "v1.9",
|
|
3
3
|
"workflow": "refill-sends-workflow",
|
|
4
4
|
"principle": "The planner chooses one exact next action and refill_sends alone executes it. Every bounded action is receipted and followed by a canonical replan. Yolo may traverse every planner-ranked existing campaign, lane, and source family; only new campaign creation requires the user.",
|
|
5
5
|
"requiredBootstrap": [
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"mustReadUntil": { "hasMore": false },
|
|
18
18
|
"validation": {
|
|
19
19
|
"workflow": "refill-sends-workflow",
|
|
20
|
-
"exactVersion": "v1.
|
|
20
|
+
"exactVersion": "v1.9",
|
|
21
21
|
"requiredTopLevelKeys": [
|
|
22
22
|
"states",
|
|
23
23
|
"gateOrder",
|
|
@@ -430,11 +430,12 @@
|
|
|
430
430
|
],
|
|
431
431
|
"terminalContract": {
|
|
432
432
|
"complete": "Projected sent plus scheduler-owned scheduled coverage meets the canonical target.",
|
|
433
|
-
"loaded_awaiting_scheduler": "
|
|
434
|
-
"blocked_retryable": "Return the exact blocker, receipt identity, and safe retry condition.",
|
|
433
|
+
"loaded_awaiting_scheduler": "Terminal, no continuation. Admissible by EITHER path: (a) every remaining exact target is complete or scheduler-owned and workspace remainingReadyOrProjectedGap is zero after the bounded scheduler wait; or (b) every gap-bearing sender lane is already prepared and its residue is ready_to_schedule surplus, so the remaining gap is scheduler/pacing-bound (ready rows awaiting placement) rather than unexposed supply — remainingReadyOrProjectedGap is NOT necessarily zero on this path. Neither path means unexposed actionable supply. Report the ready inventory and stop without a host poll loop.",
|
|
434
|
+
"blocked_retryable": "Retryable. Return the exact blocker, receipt identity, and safe retry condition. Specific blockers (for example no_forward_progress, provider outages, lease_lost) are reported UNDER this class, not as their own terminal classes.",
|
|
435
435
|
"lanes_exhausted": "Internal handoff only when another pinned existing target remains; continue with next_exact_target.",
|
|
436
436
|
"new_campaign_required": "Every existing campaign, lane, and source family is spent or infeasible; ask whether to create the proposed campaign. Refill never creates it.",
|
|
437
|
-
"
|
|
437
|
+
"source_supply_exhausted_at_rubric": "Terminal and NOT retryable — do not re-run and do not treat it as blocked_retryable. Every remaining existing-row frontier is receipt-proven exhausted at the ICP/rubric stage: the preparation receipts carry a non-retryable icp_or_rubric_rejection diagnosis, so the rows behind the scan window cannot convert into sends no matter how many times the command runs. Distinct from new_campaign_required: the source rows exist, they simply cannot pass the current rubric. Report the per-lane evidence from the note (campaign/table lane, senders covered, rows checked, rows rubric-rejected) and tell the user the only remaining fill paths are widening the rubric or adding fresh source supply. Refill changes neither on its own.",
|
|
438
|
+
"actionable_supply_not_queued": "Actionable existing-row supply (approval/generate/enrich/rubric candidates or unprocessed frontier rows) remains but no executable exact edge was dispatched for it. The census counts CONVERTIBLE rows only, de-duplicated per campaign/table lane; frontiers proven non-convertible by their own receipts are reported as source_supply_exhausted_at_rubric instead. When the run refused edges the planner did expose, the note NAMES each one (campaign:lane, sender count, actionKey, and the refusal point) — report those named blockers, not just the census. Retry with a fresh command once; if it repeats, report a planner-exposure defect with the census and the named refused edges from the note."
|
|
438
439
|
},
|
|
439
440
|
"yoloMode": {
|
|
440
441
|
"approvalSource": "explicit_yolo_flag",
|