@sellable/mcp 0.1.771 → 0.1.772

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.
@@ -594,13 +594,22 @@ function actionSourceFingerprint(action) {
594
594
  }
595
595
  function fingerprintFromPlan(plan) {
596
596
  const packet = recordValue(plan.packet) ?? {};
597
+ const targetConfig = recordValue(plan.targetConfig) ?? recordValue(packet.targetConfig) ?? {};
598
+ const revisionInputs = recordValue(targetConfig.revisionInputs) ?? {};
597
599
  const action = firstAction(plan);
598
600
  const authority = action ? decodeRefillReadinessAuthority(action) : null;
599
601
  return {
600
- planRevision: stringValue(plan.planRevision),
601
- stateRevision: stringValue(plan.stateRevision) ?? stringValue(packet.stateRevision),
602
+ planRevision: stringValue(plan.planRevision) ??
603
+ stringValue(packet.planRevision) ??
604
+ stringValue(revisionInputs.planRevision),
605
+ stateRevision: stringValue(plan.stateRevision) ??
606
+ stringValue(packet.stateRevision) ??
607
+ stringValue(revisionInputs.stateRevision),
602
608
  targetShapeRevision: stringValue(packet.targetShapeRevision) ??
603
- stringValue(packet.targetRevision),
609
+ stringValue(packet.targetRevision) ??
610
+ stringValue(plan.targetShapeRevision) ??
611
+ stringValue(plan.targetRevision) ??
612
+ stringValue(revisionInputs.targetShapeRevision),
604
613
  actionReadinessFingerprint: authority?.ok === true
605
614
  ? refillReadinessFingerprint(authority.value)
606
615
  : authority
@@ -1991,10 +2000,21 @@ function getPlanLine(plan) {
1991
2000
  fallbackSummary: stringValue(recordValue(itinerary.fallback)?.trigger) ?? "",
1992
2001
  };
1993
2002
  }
2003
+ function planRequiresEvergreenRevision(plan) {
2004
+ const packet = recordValue(plan.packet) ?? {};
2005
+ return Boolean(recordValue(plan.evergreen) ?? recordValue(packet.evergreen));
2006
+ }
1994
2007
  export function packetCoherenceFailure(plan) {
1995
2008
  const fingerprint = fingerprintFromPlan(plan);
1996
- if (!fingerprint.planRevision || !fingerprint.targetShapeRevision) {
1997
- return "missing_fingerprint";
2009
+ if (!fingerprint.targetShapeRevision) {
2010
+ return "missing_target_shape_revision";
2011
+ }
2012
+ // Active/plain campaign packets intentionally carry no planRevision.
2013
+ // planRevision fingerprints the managed evergreen lane ordering and is
2014
+ // emitted only when the planner returned an evergreen projection. Requiring
2015
+ // it for every packet rejects valid active-campaign refills before g2.
2016
+ if (planRequiresEvergreenRevision(plan) && !fingerprint.planRevision) {
2017
+ return "missing_evergreen_plan_revision";
1998
2018
  }
1999
2019
  const action = firstAction(plan);
2000
2020
  const doneReason = doneReasonFromPlan(plan);
@@ -2742,7 +2762,7 @@ async function completeTerminal(input, deps, ctx, doneReasonInput, reportInput =
2742
2762
  };
2743
2763
  }
2744
2764
  async function gatePlan(input, deps, ctx) {
2745
- const plan = await deps.readPlan(refillPlanReadInput(input, { ctx, journal: false }));
2765
+ let plan = await deps.readPlan(refillPlanReadInput(input, { ctx, journal: false }));
2746
2766
  if (plan.blocker === "workspace_access") {
2747
2767
  return {
2748
2768
  status: "blocked",
@@ -2762,23 +2782,41 @@ async function gatePlan(input, deps, ctx) {
2762
2782
  ctx.plan = plan;
2763
2783
  return completeTerminal(input, deps, ctx, "complete", { plan });
2764
2784
  }
2765
- const coherenceFailure = packetCoherenceFailure(plan);
2785
+ let coherenceFailure = packetCoherenceFailure(plan);
2786
+ if (coherenceFailure) {
2787
+ // Packet assembly reads live planner state. Give a transiently split read
2788
+ // one fresh, mutation-free chance to converge before classifying it as a
2789
+ // durable planner defect.
2790
+ const replanned = await deps.readPlan(refillPlanReadInput(input, { ctx, journal: false }));
2791
+ if (canonicalReportingCoverageComplete(replanned)) {
2792
+ ctx.plan = replanned;
2793
+ return completeTerminal(input, deps, ctx, "complete", {
2794
+ plan: replanned,
2795
+ });
2796
+ }
2797
+ const replannedCoherenceFailure = packetCoherenceFailure(replanned);
2798
+ if (!replannedCoherenceFailure) {
2799
+ plan = replanned;
2800
+ coherenceFailure = null;
2801
+ }
2802
+ else {
2803
+ coherenceFailure = replannedCoherenceFailure;
2804
+ plan = replanned;
2805
+ }
2806
+ }
2766
2807
  if (coherenceFailure) {
2767
2808
  await safeJournalAppend(ctx, deps, deps.journal.renderPlanSection({
2768
2809
  chosenSummary: `packet_incoherent: ${coherenceFailure}`,
2769
2810
  itinerarySummaries: [],
2770
- fallbackSummary: "replan once before blocking",
2811
+ fallbackSummary: "fresh replan remained incoherent; terminalize and release the exact run",
2771
2812
  }));
2772
- return {
2773
- status: "blocked",
2813
+ ctx.plan = plan;
2814
+ return completeTerminal(input, deps, ctx, "blocked", {
2774
2815
  blocker: "packet_incoherent",
2775
- runId: ctx.runId,
2776
- fence: ctx.fence,
2777
- gate: ctx.gate,
2778
2816
  guidance: `Planner returned an incoherent packet: ${coherenceFailure}.`,
2779
- report: { coherenceFailure, plan },
2780
- journalPath: ctx.journalPath,
2781
- };
2817
+ coherenceFailure,
2818
+ plan,
2819
+ });
2782
2820
  }
2783
2821
  const action = firstAction(plan);
2784
2822
  const doneReason = doneReasonFromPlan(plan);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.771",
3
+ "version": "0.1.772",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",