Handle numbered Scattermind build order labels
This commit is contained in:
@@ -1934,6 +1934,44 @@ try {
|
|||||||
assert.equal(storedScattermindRow.handoff.readiness.status, 'ready');
|
assert.equal(storedScattermindRow.handoff.readiness.status, 'ready');
|
||||||
assert.deepEqual(storedScattermindRow.handoff.warnings, []);
|
assert.deepEqual(storedScattermindRow.handoff.warnings, []);
|
||||||
|
|
||||||
|
const numberedMarkdownBuildOrderResponse = await fetch(`${base}/api/rank-feedback`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
referenceCode: 'SM-NUMBERED-BUILD-ORDER-1',
|
||||||
|
ideaText: 'Scattermind generated a paid Concept Map with numbered Markdown labels in the Build Order lens.',
|
||||||
|
context: 'Solo builder. Avoid account dashboards before the first proof.',
|
||||||
|
mode: 'mvp',
|
||||||
|
fullReadingJson: JSON.stringify({
|
||||||
|
working_name: 'Numbered Build Order',
|
||||||
|
opening_reflection: 'The Concept Map has a clear continuation order, but the labels are formatted for humans, not strict JSON.',
|
||||||
|
lenses: {
|
||||||
|
risk: { title: 'What Can Mislead You', content: 'Avoid account dashboards before the first proof works.' },
|
||||||
|
channel: {
|
||||||
|
title: 'Build Order',
|
||||||
|
content: '1. **Build first:** Numbered source-traced preview — turn this Concept Map into one defended first move.\n2. **Test manually:** Ask one tired user whether the copied handoff tells them what to do next.\n3. **Defer:** Visual polish until the proof says the handoff is understandable.\n4. **Probably noise:** Account dashboard with saved workspaces before proof.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
questions_to_sit_with: ['Can a tired user act from the first numbered move?'],
|
||||||
|
closing_note: 'Use the numbered source-traced preview as the first 48-hour move.',
|
||||||
|
reference_code: 'SM-NUMBERED-BUILD-ORDER-1',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
assert.equal(numberedMarkdownBuildOrderResponse.status, 200);
|
||||||
|
const numberedMarkdownBuildOrder = await numberedMarkdownBuildOrderResponse.json();
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.input.provenance.artifactId, 'SM-NUMBERED-BUILD-ORDER-1');
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.input.optionCount, 4);
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.ranked[0].id, 'build-order-1');
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.ranked[0].title, 'Numbered source-traced preview');
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.ranked[0].lane.id, 'do');
|
||||||
|
assert.match(numberedMarkdownBuildOrder.ranked[0].provenance.sourceQuote, /Build first.*Numbered source-traced preview/);
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.ranked.find(item => item.id === 'build-order-2').lane.id, 'test');
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.ranked.find(item => item.id === 'build-order-3').lane.id, 'defer');
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.ranked.find(item => item.id === 'build-order-4').lane.id, 'park');
|
||||||
|
assert.equal(numberedMarkdownBuildOrder.handoff.readiness.status, 'ready');
|
||||||
|
assert.deepEqual(numberedMarkdownBuildOrder.handoff.warnings, []);
|
||||||
|
|
||||||
const candidateActionsAliasResponse = await fetch(`${base}/api/rank-feedback`, {
|
const candidateActionsAliasResponse = await fetch(`${base}/api/rank-feedback`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
|||||||
@@ -1199,11 +1199,19 @@ const buildOrderLabelSeparator = '\\s*(?::|,|[-–—])\\s*';
|
|||||||
const buildOrderLabelPattern = '(build first|build this first|start here|start with|start by|ship first|ship this first|first week|week one|first-week build order|continue first|make tangible first|make tangible|try next|test first|prove first|evidence next|learn next|test manually|validate manually|manual proof|validate next|hold for later|leave out|skip for now|not yet|defer|set aside|out of scope|probably noise|park|do not build yet|don\'t build yet)';
|
const buildOrderLabelPattern = '(build first|build this first|start here|start with|start by|ship first|ship this first|first week|week one|first-week build order|continue first|make tangible first|make tangible|try next|test first|prove first|evidence next|learn next|test manually|validate manually|manual proof|validate next|hold for later|leave out|skip for now|not yet|defer|set aside|out of scope|probably noise|park|do not build yet|don\'t build yet)';
|
||||||
const buildOrderLabelRegex = new RegExp(`^${buildOrderLabelPattern}${buildOrderLabelSeparator}`, 'i');
|
const buildOrderLabelRegex = new RegExp(`^${buildOrderLabelPattern}${buildOrderLabelSeparator}`, 'i');
|
||||||
|
|
||||||
|
function normalizeBuildOrderFragment(fragment = '') {
|
||||||
|
return cleanMultiline(fragment, 600)
|
||||||
|
.replace(/^\s*(?:[-*•]|\d+[.)])\s*/, '')
|
||||||
|
.replace(/^\s*\*\*([^*:]{2,80})\s*:?\*\*\s*(?::|[-–—])?\s*/i, '$1: ')
|
||||||
|
.replace(/^\s*__([^_:]{2,80})\s*:?__\s*(?::|[-–—])?\s*/i, '$1: ')
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
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 => part.trim())
|
.map(part => normalizeBuildOrderFragment(part))
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user