Preserve Scattermind action signals in Ranker handoff
This commit is contained in:
@@ -647,6 +647,9 @@ function normalizeFeatureOption(item, index, fallbackId = 'feature', defaultSour
|
||||
const evidenceNeeded = cleanText(raw.evidenceNeeded || raw.evidence || raw.test || raw.evidenceQuestion || raw.questionToAnswer || '', 260);
|
||||
const userValue = cleanText(raw.userValue || raw.value || raw.outcome || raw.why, 260);
|
||||
const risk = cleanText(raw.risk || raw.assumption || raw.unknown || '', 220);
|
||||
const nextStep = cleanText(raw.nextStep || raw.nextAction || raw.firstStep || raw.manualStep || raw.actionToTake || '', 260);
|
||||
const successSignal = cleanText(raw.successSignal || raw.successCriteria || raw.successMetric || raw.greenLight || raw.signalToSee || '', 260);
|
||||
const killSignal = cleanText(raw.killSignal || raw.stopSignal || raw.redFlag || raw.failureSignal || raw.cutIf || '', 260);
|
||||
const sourceSection = cleanText(raw.sourceSection || raw.section || raw.lane || raw.origin || defaultSourceSection, 80);
|
||||
const recommendedLane = cleanText(raw.recommendedLane || raw.laneHint || raw.suggestedLane || defaultRecommendedLane || '', 40).toLowerCase();
|
||||
const descriptionParts = [
|
||||
@@ -654,6 +657,9 @@ function normalizeFeatureOption(item, index, fallbackId = 'feature', defaultSour
|
||||
userValue && `User value: ${userValue}`,
|
||||
evidenceNeeded && `Evidence needed: ${evidenceNeeded}`,
|
||||
risk && `Risk: ${risk}`,
|
||||
nextStep && `Next step: ${nextStep}`,
|
||||
successSignal && `Success signal: ${successSignal}`,
|
||||
killSignal && `Kill signal: ${killSignal}`,
|
||||
proofSteps.length && `Proof steps: ${proofSteps.join('; ')}`,
|
||||
dependencies.length && `Dependencies: ${dependencies.join(', ')}`,
|
||||
].filter(Boolean);
|
||||
@@ -661,7 +667,7 @@ function normalizeFeatureOption(item, index, fallbackId = 'feature', defaultSour
|
||||
id: cleanText(raw.id || raw.key || `${fallbackId}-${index + 1}`, 80) || `${fallbackId}-${index + 1}`,
|
||||
title,
|
||||
description: cleanText(descriptionParts.join(' '), 760),
|
||||
factors: { userValue, evidenceNeeded, risk, proofSteps, dependencies, recommendedLane, metricHints: cleanMetricHints(raw) },
|
||||
factors: { userValue, evidenceNeeded, risk, nextStep, successSignal, killSignal, proofSteps, dependencies, recommendedLane, metricHints: cleanMetricHints(raw) },
|
||||
provenance: {
|
||||
sourceId: cleanText(raw.sourceId || raw.sourceArtifactId || raw.id || '', 120),
|
||||
sourceSection,
|
||||
@@ -927,6 +933,7 @@ function evidenceQuestionFor(option) {
|
||||
|
||||
function nextStepFor(option) {
|
||||
if (!option) return '';
|
||||
if (option.factors?.nextStep) return option.factors.nextStep;
|
||||
if (option.lane?.id === 'do') return `Run one manual proof of “${option.title}” before building supporting machinery.`;
|
||||
if (option.lane?.id === 'test') return `Design the smallest evidence test for “${option.title}” and collect signal from real users.`;
|
||||
if (option.lane?.id === 'defer') return `Keep “${option.title}” sequenced after the active proof; do not parallel-build it.`;
|
||||
@@ -935,6 +942,7 @@ function nextStepFor(option) {
|
||||
|
||||
function successSignalFor(option) {
|
||||
if (!option) return '';
|
||||
if (option.factors?.successSignal) return option.factors.successSignal;
|
||||
if (option.metrics?.revenue >= 6.4) return 'A real prospect asks for the outcome, accepts a price, or requests the next step.';
|
||||
if (option.lane?.id === 'do') return 'At least 2 of 3 real users can name why this should be first and what they would do next.';
|
||||
if (option.lane?.id === 'test') return 'The test produces a clear yes/no learning, not polite interest.';
|
||||
@@ -943,6 +951,7 @@ function successSignalFor(option) {
|
||||
|
||||
function killSignalFor(option) {
|
||||
if (!option) return '';
|
||||
if (option.factors?.killSignal) return option.factors.killSignal;
|
||||
if (option.metrics?.nonGoalConflicts?.length) return 'It still conflicts with the source guardrails after review.';
|
||||
if (option.metrics?.feasibility <= 4.5) return 'The proof slice needs platform work before any user signal exists.';
|
||||
return 'People understand the idea but do not take, request, or value the next step.';
|
||||
@@ -1060,6 +1069,8 @@ function compactBuildItems(items = []) {
|
||||
reason: item.reason,
|
||||
nextStep: item.nextStep,
|
||||
evidenceQuestion: item.evidenceQuestion,
|
||||
successSignal: item.successSignal,
|
||||
killSignal: item.killSignal,
|
||||
concern: item.concern,
|
||||
sourceSection: item.provenance?.sourceSection || '',
|
||||
sourceId: item.provenance?.sourceId || '',
|
||||
@@ -1089,6 +1100,9 @@ function createHandoffContract({ ranked, provenance, decisionContext }) {
|
||||
originalId: item.provenance?.originalId || '',
|
||||
idNormalized: Boolean(item.provenance?.idNormalized),
|
||||
evidenceNeeded: item.factors?.evidenceNeeded || '',
|
||||
nextStep: item.nextStep || '',
|
||||
successSignal: item.successSignal || '',
|
||||
killSignal: item.killSignal || '',
|
||||
nonGoalConflicts: item.metrics?.nonGoalConflicts || [],
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user