Preserve Scattermind build-order proof signals
This commit is contained in:
@@ -1087,6 +1087,33 @@ try {
|
|||||||
assert.ok(lensOnly.ranked.find(item => item.id === 'build-order-4').metrics.nonGoalConflicts.length >= 1);
|
assert.ok(lensOnly.ranked.find(item => item.id === 'build-order-4').metrics.nonGoalConflicts.length >= 1);
|
||||||
assert.deepEqual(lensOnly.handoff.warnings, []);
|
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`, {
|
const scattermindPaidShapeResponse = await fetch(`${base}/api/rank-feedback`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
|||||||
@@ -1216,7 +1216,7 @@ function normalizeBuildOrderFragment(fragment = '') {
|
|||||||
function sentenceFragments(text = '') {
|
function sentenceFragments(text = '') {
|
||||||
return cleanMultiline(text, 4000)
|
return cleanMultiline(text, 4000)
|
||||||
.replace(new RegExp(`\\s+${buildOrderLabelPattern}${buildOrderLabelSeparator}`, 'gi'), '\n$1: ')
|
.replace(new RegExp(`\\s+${buildOrderLabelPattern}${buildOrderLabelSeparator}`, 'gi'), '\n$1: ')
|
||||||
.split(/\n|;|\s+[•-]\s+/)
|
.split(/\n|;|\s+•\s+/)
|
||||||
.map(part => normalizeBuildOrderFragment(part))
|
.map(part => normalizeBuildOrderFragment(part))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
@@ -1240,6 +1240,8 @@ function optionsFromBuildOrderText(text = '', sourceSection = 'concept-map.lense
|
|||||||
const labelled = fragments.filter(fragment => laneFromBuildOrderLabel(fragment));
|
const labelled = fragments.filter(fragment => laneFromBuildOrderLabel(fragment));
|
||||||
return labelled.map((fragment, index) => {
|
return labelled.map((fragment, index) => {
|
||||||
const lane = laneFromBuildOrderLabel(fragment);
|
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 {
|
return {
|
||||||
id: `build-order-${index + 1}`,
|
id: `build-order-${index + 1}`,
|
||||||
action: titleFromBuildOrderFragment(fragment),
|
action: titleFromBuildOrderFragment(fragment),
|
||||||
@@ -1251,6 +1253,8 @@ function optionsFromBuildOrderText(text = '', sourceSection = 'concept-map.lense
|
|||||||
: lane === 'validate-next'
|
: lane === 'validate-next'
|
||||||
? 'Collect the smallest real signal before promoting this into the build lane.'
|
? 'Collect the smallest real signal before promoting this into the build lane.'
|
||||||
: '',
|
: '',
|
||||||
|
successSignal,
|
||||||
|
killSignal: failureSignal,
|
||||||
suggestedLane: lane,
|
suggestedLane: lane,
|
||||||
rankerHints: lane === 'do-first'
|
rankerHints: lane === 'do-first'
|
||||||
? { value: 8, effort: 2, confidence: 7, urgency: 7, risk: 2 }
|
? { value: 8, effort: 2, confidence: 7, urgency: 7, risk: 2 }
|
||||||
|
|||||||
Reference in New Issue
Block a user