Preserve Scattermind build-order proof signals

This commit is contained in:
OpenClaw Bot
2026-05-27 21:08:00 +02:00
parent 18c85b21dc
commit 4f0553c26d
2 changed files with 32 additions and 1 deletions
+27
View File
@@ -1087,6 +1087,33 @@ try {
assert.ok(lensOnly.ranked.find(item => item.id === 'build-order-4').metrics.nonGoalConflicts.length >= 1);
assert.deepEqual(lensOnly.handoff.warnings, []);
const signalLensResponse = await fetch(`${base}/api/rank-feedback`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sourceName: 'Scattermind',
reference_code: 'SM-SIGNAL-LENS',
working_name: 'Signal-rich Build Order',
ideaText: 'A paid Concept Map names the success and failure signal directly in its Build Order lens.',
context: 'Solo builder. Manual proof first. Avoid accounts and dashboards until the signal is real.',
mode: 'mvp',
lenses: {
risk: 'Avoid accounts and dashboards until the signal is real.',
channel: 'Build first: Manual invite proof - ask five named buyers before building signup UI. Success signal: two people ask for a date. Failure signal: nobody replies with a concrete yes. Test manually: One-page promise - show the offer and collect yes/no replies. Green flag: people ask how to book. Red flag: people only say interesting.',
},
}),
});
assert.equal(signalLensResponse.status, 200);
const signalLens = await signalLensResponse.json();
assert.equal(signalLens.ranked[0].id, 'build-order-1');
assert.equal(signalLens.ranked[0].factors.successSignal, 'two people ask for a date');
assert.equal(signalLens.ranked[0].factors.killSignal, 'nobody replies with a concrete yes');
assert.equal(signalLens.handoff.activeSlice.proof.successSignal, 'two people ask for a date');
assert.equal(signalLens.handoff.activeSlice.proof.killSignal, 'nobody replies with a concrete yes');
assert.equal(signalLens.ranked.find(item => item.id === 'build-order-2').factors.successSignal, 'people ask how to book');
assert.equal(signalLens.ranked.find(item => item.id === 'build-order-2').factors.killSignal, 'people only say interesting');
assert.deepEqual(signalLens.handoff.warnings, []);
const scattermindPaidShapeResponse = await fetch(`${base}/api/rank-feedback`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
+5 -1
View File
@@ -1216,7 +1216,7 @@ function normalizeBuildOrderFragment(fragment = '') {
function sentenceFragments(text = '') {
return cleanMultiline(text, 4000)
.replace(new RegExp(`\\s+${buildOrderLabelPattern}${buildOrderLabelSeparator}`, 'gi'), '\n$1: ')
.split(/\n|;|\s+[•-]\s+/)
.split(/\n|;|\s+\s+/)
.map(part => normalizeBuildOrderFragment(part))
.filter(Boolean);
}
@@ -1240,6 +1240,8 @@ function optionsFromBuildOrderText(text = '', sourceSection = 'concept-map.lense
const labelled = fragments.filter(fragment => laneFromBuildOrderLabel(fragment));
return labelled.map((fragment, index) => {
const lane = laneFromBuildOrderLabel(fragment);
const successSignal = signalFromThreadText(fragment, ['success signal', 'green flag', 'working if', 'working when']);
const failureSignal = signalFromThreadText(fragment, ['failure signal', 'red flag', 'failing if', 'failing when', 'stop if', 'kill signal']);
return {
id: `build-order-${index + 1}`,
action: titleFromBuildOrderFragment(fragment),
@@ -1251,6 +1253,8 @@ function optionsFromBuildOrderText(text = '', sourceSection = 'concept-map.lense
: lane === 'validate-next'
? 'Collect the smallest real signal before promoting this into the build lane.'
: '',
successSignal,
killSignal: failureSignal,
suggestedLane: lane,
rankerHints: lane === 'do-first'
? { value: 8, effort: 2, confidence: 7, urgency: 7, risk: 2 }