Carry Concept Map thread signals into Ranker

This commit is contained in:
OpenClaw Bot
2026-05-28 00:38:31 +02:00
parent 066717221c
commit 4212b4d7c8
2 changed files with 79 additions and 22 deletions
+37 -21
View File
@@ -1663,21 +1663,6 @@ function optionsFromBody(body = {}) {
questionSource.sourceSection || 'questionsToSitWith',
'Question to sit with'
);
if (buildOrderOptions.length) {
const proofLens = objectFrom(conceptMapLenses.question || conceptMapLenses.proof || conceptMapLenses.validation || conceptMapLenses.evidence);
const proofLensText = lensContent(conceptMapLenses.question)
|| lensContent(conceptMapLenses.proof)
|| lensContent(conceptMapLenses.validation)
|| lensContent(conceptMapLenses.evidence)
|| '';
const proofSourceTitle = cleanText(proofLens.title || 'Proof Steps', 140);
const proofOptions = optionsFromProofLensText(proofLensText, 'concept-map.lenses.question', proofSourceTitle);
return normalizeCandidateGroup([
{ items: buildOrderOptions, sourceSection: 'concept-map.lenses.channel' },
...(proofOptions.length ? [{ items: proofOptions, sourceSection: 'concept-map.lenses.question', defaultLane: 'validate-next' }] : []),
...(questionOptions.length ? [{ items: questionOptions, sourceSection: questionSource.sourceSection || 'questionsToSitWith', defaultLane: 'validate-next' }] : []),
]);
}
const actionThreadSource = firstArraySource([
{ items: conceptMap.threads_to_hold || conceptMap.threadsToHold || conceptMap.actionThreads || conceptMap.action_threads, sourceSection: 'concept-map.threadsToHold' },
{ items: snapshot.threads_to_hold || snapshot.threadsToHold || snapshot.actionThreads || snapshot.action_threads, sourceSection: 'snapshot.threadsToHold' },
@@ -1690,6 +1675,23 @@ function optionsFromBody(body = {}) {
actionThreadSource.sourceSection || 'threadsToHold',
'Thread to hold'
);
if (buildOrderOptions.length) {
const proofLens = objectFrom(conceptMapLenses.question || conceptMapLenses.proof || conceptMapLenses.validation || conceptMapLenses.evidence);
const proofLensText = lensContent(conceptMapLenses.question)
|| lensContent(conceptMapLenses.proof)
|| lensContent(conceptMapLenses.validation)
|| lensContent(conceptMapLenses.evidence)
|| '';
const proofSourceTitle = cleanText(proofLens.title || 'Proof Steps', 140);
const proofOptions = optionsFromProofLensText(proofLensText, 'concept-map.lenses.question', proofSourceTitle);
const supplementalActionThreadOptions = actionThreadOptions.filter(item => item.greenFlag || item.redFlag || ['defer', 'park'].includes(item.suggestedLane));
return normalizeCandidateGroup([
{ items: buildOrderOptions, sourceSection: 'concept-map.lenses.channel' },
...(supplementalActionThreadOptions.length ? [{ items: supplementalActionThreadOptions, sourceSection: actionThreadSource.sourceSection || 'threadsToHold' }] : []),
...(proofOptions.length ? [{ items: proofOptions, sourceSection: 'concept-map.lenses.question', defaultLane: 'validate-next' }] : []),
...(questionOptions.length ? [{ items: questionOptions, sourceSection: questionSource.sourceSection || 'questionsToSitWith', defaultLane: 'validate-next' }] : []),
]);
}
if (actionThreadOptions.length >= 2) return normalizeCandidateGroup([{ items: actionThreadOptions, sourceSection: actionThreadSource.sourceSection || 'threadsToHold' }]);
if (actionThreadOptions.length === 1 && questionOptions.length) {
return normalizeCandidateGroup([
@@ -1894,6 +1896,18 @@ function killSignalFor(option) {
return 'People understand the idea but do not take, request, or value the next step.';
}
function carriedProofSignalFor(active, ranked = [], signalKey = 'successSignal') {
if (!active) return '';
if (active.factors?.[signalKey]) return active.factors[signalKey];
const threadSignal = ranked.find(item => (
item.id !== active.id
&& /threads(?:ToHold|_to_hold)?/i.test(item.provenance?.sourceSection || '')
&& item.factors?.[signalKey]
));
if (threadSignal?.factors?.[signalKey]) return threadSignal.factors[signalKey];
return signalKey === 'killSignal' ? killSignalFor(active) : successSignalFor(active);
}
function scoringNotesFor(option) {
const notes = [];
const m = option.metrics || {};
@@ -1945,6 +1959,8 @@ function createDecisionBrief({ idea, context, mode, ranked, provenance, decision
const activeSourceQuote = cleanText(top?.provenance?.sourceQuote || '', 260);
const activeSourceTitle = cleanText(top?.provenance?.sourceTitle || '', 140);
const activeProofScript = top ? proofScriptFor(top, provenance) : '';
const activeSuccessSignal = carriedProofSignalFor(top, ranked, 'successSignal');
const activeKillSignal = carriedProofSignalFor(top, ranked, 'killSignal');
const firstScreen = top ? {
headline: `Build only this first: ${top.title}`,
primaryAction: nextStepFor(top),
@@ -1954,8 +1970,8 @@ function createDecisionBrief({ idea, context, mode, ranked, provenance, decision
sourceAnchor: activeSourceAnchor,
sourceTitle: activeSourceTitle,
sourceQuote: activeSourceQuote,
passSignal: successSignalFor(top),
stopSignal: killSignalFor(top),
passSignal: activeSuccessSignal,
stopSignal: activeKillSignal,
proofCadence: 'Run one tiny proof cycle, then rerank before adding surface area.',
holdBack: deferred.slice(0, 3).map(item => ({ title: item.title, lane: item.lane?.label || 'Not now', reason: reasonFor(item) })),
guardrails: (decisionContext?.nonGoals || []).slice(0, 3),
@@ -1967,8 +1983,8 @@ function createDecisionBrief({ idea, context, mode, ranked, provenance, decision
firstProofStep: nextStepFor(top),
evidenceQuestion: evidenceQuestionFor(top),
proofScript: activeProofScript,
passSignal: successSignalFor(top),
stopSignal: killSignalFor(top),
passSignal: activeSuccessSignal,
stopSignal: activeKillSignal,
proofCadence: 'Run one tiny proof cycle, then rerank before adding surface area.',
doNotStartYet: deferred.slice(0, 3).map(item => item.title),
sourceAnchor: activeSourceAnchor,
@@ -2136,8 +2152,8 @@ function activeSliceFor({ ranked = [], provenance = {}, readiness = {} }) {
nextStep: nextStepFor(active),
evidenceQuestion: evidenceQuestionFor(active),
proofScript: proofScriptFor(active, provenance),
successSignal: successSignalFor(active),
killSignal: killSignalFor(active),
successSignal: carriedProofSignalFor(active, ranked, 'successSignal'),
killSignal: carriedProofSignalFor(active, ranked, 'killSignal'),
},
source: {
artifactId: provenance?.artifactId || '',