Carry Concept Map questions with build order

This commit is contained in:
OpenClaw Bot
2026-05-28 00:33:33 +02:00
parent 6a2cc34759
commit 066717221c
2 changed files with 56 additions and 15 deletions
+43 -3
View File
@@ -936,6 +936,43 @@ try {
assert.equal(experimentSection.ranked.find(item => item.id === 'accounted-test-library').lane.id, 'park'); assert.equal(experimentSection.ranked.find(item => item.id === 'accounted-test-library').lane.id, 'park');
assert.deepEqual(experimentSection.handoff.warnings, []); assert.deepEqual(experimentSection.handoff.warnings, []);
const buildOrderQuestionsResponse = await fetch(`${base}/api/rank-feedback`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sourceName: 'Scattermind',
artifactId: 'concept_map_build_order_questions',
snapshotTitle: 'Build Order with decision questions',
originalPrompt: 'Clarify a continuation engine and name what to build first.',
idea: 'A full Scattermind Concept Map emitted a Build Order lens plus questions to sit with.',
mode: 'mvp',
conceptMap: {
lenses: {
channel: {
title: 'Build Order',
content: 'Build first: Manual bridge handoff preview — turn one Concept Map into a defended first move. Test manually: Show the copied handoff to 3 tired builders and ask what they would do next. Defer: Saved workspaces until the copyable handoff proves useful. Probably noise: Team dashboard and billing layer.',
},
question: {
title: 'Proof Steps',
content: 'Ask 3 tired builders to read the handoff and tell you the first move without extra explanation.',
},
},
questions_to_sit_with: [
'Can the user explain why the first move wins after reading only the handoff?',
'What evidence would make the saved workspace worth reopening later?',
],
},
}),
});
assert.equal(buildOrderQuestionsResponse.status, 200);
const buildOrderQuestions = await buildOrderQuestionsResponse.json();
assert.equal(buildOrderQuestions.input.optionCount, 7, 'Build Order lens should carry Proof Steps and questions into the candidate set');
assert.equal(buildOrderQuestions.ranked[0].provenance.sourceSection, 'concept-map.lenses.channel');
assert.ok(buildOrderQuestions.ranked.some(item => item.provenance.sourceSection === 'concept-map.questionsToSitWith'));
assert.equal(buildOrderQuestions.ranked.find(item => /Can the user explain why the first move wins/i.test(item.title)).lane.id, 'test');
assert.ok(buildOrderQuestions.buildOrder.validateNext.some(id => buildOrderQuestions.ranked.find(item => item.id === id)?.provenance.sourceSection === 'concept-map.questionsToSitWith'));
assert.match(buildOrderQuestions.handoff.copyableText, /Can the user explain why the first move wins/);
const emptyWrapperResponse = await fetch(`${base}/api/rank-feedback`, { const emptyWrapperResponse = await fetch(`${base}/api/rank-feedback`, {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
@@ -1265,10 +1302,11 @@ try {
assert.equal(privateReadingEnvelope.input.provenance.artifactId, 'SM-PRIVATE1'); assert.equal(privateReadingEnvelope.input.provenance.artifactId, 'SM-PRIVATE1');
assert.equal(privateReadingEnvelope.input.provenance.snapshotTitle, 'Local Workshop Starter'); assert.equal(privateReadingEnvelope.input.provenance.snapshotTitle, 'Local Workshop Starter');
assert.match(privateReadingEnvelope.input.provenance.originalPrompt, /Scattermind clarified/); assert.match(privateReadingEnvelope.input.provenance.originalPrompt, /Scattermind clarified/);
assert.equal(privateReadingEnvelope.input.optionCount, 6); assert.equal(privateReadingEnvelope.input.optionCount, 7);
assert.equal(privateReadingEnvelope.ranked[0].id, 'build-order-1'); assert.equal(privateReadingEnvelope.ranked[0].id, 'build-order-1');
assert.equal(privateReadingEnvelope.ranked[0].provenance.sourceSection, 'concept-map.lenses.channel'); assert.equal(privateReadingEnvelope.ranked[0].provenance.sourceSection, 'concept-map.lenses.channel');
assert.equal(privateReadingEnvelope.ranked.find(item => item.id === 'proof-step-1').lane.id, 'test'); assert.equal(privateReadingEnvelope.ranked.find(item => item.id === 'proof-step-1').lane.id, 'test');
assert.ok(privateReadingEnvelope.ranked.some(item => item.provenance.sourceSection === 'concept-map.questionsToSitWith'));
assert.equal(privateReadingEnvelope.ranked.find(item => item.id === 'build-order-4').lane.id, 'park'); assert.equal(privateReadingEnvelope.ranked.find(item => item.id === 'build-order-4').lane.id, 'park');
assert.ok(privateReadingEnvelope.input.decisionContext.nonGoals.includes('Avoid accounts, saved calendars, and payment dashboards until one workshop has real interest')); assert.ok(privateReadingEnvelope.input.decisionContext.nonGoals.includes('Avoid accounts, saved calendars, and payment dashboards until one workshop has real interest'));
assert.deepEqual(privateReadingEnvelope.handoff.warnings, []); assert.deepEqual(privateReadingEnvelope.handoff.warnings, []);
@@ -2065,12 +2103,13 @@ try {
assert.equal(storedScattermindRow.input.provenance.artifactId, 'SM-STORED-1'); assert.equal(storedScattermindRow.input.provenance.artifactId, 'SM-STORED-1');
assert.equal(storedScattermindRow.input.provenance.snapshotTitle, 'Stored Row Bridge'); assert.equal(storedScattermindRow.input.provenance.snapshotTitle, 'Stored Row Bridge');
assert.match(storedScattermindRow.input.provenance.originalPrompt, /actual stored row ranked/); assert.match(storedScattermindRow.input.provenance.originalPrompt, /actual stored row ranked/);
assert.equal(storedScattermindRow.input.optionCount, 4); assert.equal(storedScattermindRow.input.optionCount, 5);
assert.equal(storedScattermindRow.ranked[0].id, 'build-order-1'); assert.equal(storedScattermindRow.ranked[0].id, 'build-order-1');
assert.equal(storedScattermindRow.ranked[0].provenance.sourceTitle, 'Build Order'); assert.equal(storedScattermindRow.ranked[0].provenance.sourceTitle, 'Build Order');
assert.match(storedScattermindRow.ranked[0].provenance.sourceQuote, /Stored-row build-order preview/); assert.match(storedScattermindRow.ranked[0].provenance.sourceQuote, /Stored-row build-order preview/);
assert.ok(storedScattermindRow.input.decisionContext.nonGoals.includes('Avoid account dashboards and saved workspaces before one user acts')); assert.ok(storedScattermindRow.input.decisionContext.nonGoals.includes('Avoid account dashboards and saved workspaces before one user acts'));
assert.equal(storedScattermindRow.ranked.find(item => item.id === 'build-order-4').lane.id, 'park'); assert.equal(storedScattermindRow.ranked.find(item => item.id === 'build-order-4').lane.id, 'park');
assert.ok(storedScattermindRow.ranked.some(item => item.provenance.sourceSection === 'concept-map.questionsToSitWith'));
assert.equal(storedScattermindRow.handoff.readiness.status, 'ready'); assert.equal(storedScattermindRow.handoff.readiness.status, 'ready');
assert.deepEqual(storedScattermindRow.handoff.warnings, []); assert.deepEqual(storedScattermindRow.handoff.warnings, []);
@@ -2101,7 +2140,7 @@ try {
assert.equal(numberedMarkdownBuildOrderResponse.status, 200); assert.equal(numberedMarkdownBuildOrderResponse.status, 200);
const numberedMarkdownBuildOrder = await numberedMarkdownBuildOrderResponse.json(); const numberedMarkdownBuildOrder = await numberedMarkdownBuildOrderResponse.json();
assert.equal(numberedMarkdownBuildOrder.input.provenance.artifactId, 'SM-NUMBERED-BUILD-ORDER-1'); assert.equal(numberedMarkdownBuildOrder.input.provenance.artifactId, 'SM-NUMBERED-BUILD-ORDER-1');
assert.equal(numberedMarkdownBuildOrder.input.optionCount, 4); assert.equal(numberedMarkdownBuildOrder.input.optionCount, 5);
assert.equal(numberedMarkdownBuildOrder.ranked[0].id, 'build-order-1'); assert.equal(numberedMarkdownBuildOrder.ranked[0].id, 'build-order-1');
assert.equal(numberedMarkdownBuildOrder.ranked[0].title, 'Numbered source-traced preview'); assert.equal(numberedMarkdownBuildOrder.ranked[0].title, 'Numbered source-traced preview');
assert.equal(numberedMarkdownBuildOrder.ranked[0].lane.id, 'do'); assert.equal(numberedMarkdownBuildOrder.ranked[0].lane.id, 'do');
@@ -2109,6 +2148,7 @@ try {
assert.equal(numberedMarkdownBuildOrder.ranked.find(item => item.id === 'build-order-2').lane.id, 'test'); 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-3').lane.id, 'defer');
assert.equal(numberedMarkdownBuildOrder.ranked.find(item => item.id === 'build-order-4').lane.id, 'park'); assert.equal(numberedMarkdownBuildOrder.ranked.find(item => item.id === 'build-order-4').lane.id, 'park');
assert.ok(numberedMarkdownBuildOrder.ranked.some(item => item.provenance.sourceSection === 'concept-map.questionsToSitWith'));
assert.equal(numberedMarkdownBuildOrder.handoff.readiness.status, 'ready'); assert.equal(numberedMarkdownBuildOrder.handoff.readiness.status, 'ready');
assert.deepEqual(numberedMarkdownBuildOrder.handoff.warnings, []); assert.deepEqual(numberedMarkdownBuildOrder.handoff.warnings, []);
+13 -12
View File
@@ -1651,6 +1651,18 @@ function optionsFromBody(body = {}) {
140 140
); );
const buildOrderOptions = optionsFromBuildOrderText(buildOrderText, 'concept-map.lenses.channel', buildOrderSourceTitle); const buildOrderOptions = optionsFromBuildOrderText(buildOrderText, 'concept-map.lenses.channel', buildOrderSourceTitle);
const questionSource = firstArraySource([
{ items: conceptMap.questions_to_sit_with || conceptMap.questionsToSitWith || conceptMap.evidenceQuestions || conceptMap.evidence_questions || conceptMap.proofQuestions || conceptMap.proof_questions || conceptMap.validationQuestions || conceptMap.validation_questions || conceptMap.decisionQuestions || conceptMap.decision_questions || conceptMap.questionsToAnswer || conceptMap.questions_to_answer || conceptMap.followupQuestions || conceptMap.followup_questions || conceptMap.openQuestions || conceptMap.open_questions, sourceSection: 'concept-map.questionsToSitWith' },
{ items: snapshot.questions_to_sit_with || snapshot.questionsToSitWith || snapshot.evidenceQuestions || snapshot.evidence_questions || snapshot.proofQuestions || snapshot.proof_questions || snapshot.validationQuestions || snapshot.validation_questions || snapshot.decisionQuestions || snapshot.decision_questions || snapshot.questionsToAnswer || snapshot.questions_to_answer || snapshot.followupQuestions || snapshot.followup_questions || snapshot.openQuestions || snapshot.open_questions, sourceSection: 'snapshot.questionsToSitWith' },
{ items: envelope.questions_to_sit_with || envelope.questionsToSitWith || envelope.evidenceQuestions || envelope.evidence_questions || envelope.proofQuestions || envelope.proof_questions || envelope.validationQuestions || envelope.validation_questions || envelope.decisionQuestions || envelope.decision_questions || envelope.questionsToAnswer || envelope.questions_to_answer || envelope.followupQuestions || envelope.followup_questions || envelope.openQuestions || envelope.open_questions, sourceSection: 'ranker-input.questionsToSitWith' },
{ items: featureSet.questions_to_sit_with || featureSet.questionsToSitWith || featureSet.evidenceQuestions || featureSet.evidence_questions || featureSet.proofQuestions || featureSet.proof_questions || featureSet.validationQuestions || featureSet.validation_questions || featureSet.decisionQuestions || featureSet.decision_questions || featureSet.questionsToAnswer || featureSet.questions_to_answer || featureSet.followupQuestions || featureSet.followup_questions || featureSet.openQuestions || featureSet.open_questions, sourceSection: 'feature-set.questionsToSitWith' },
{ items: body.questions_to_sit_with || body.questionsToSitWith || body.evidenceQuestions || body.evidence_questions || body.proofQuestions || body.proof_questions || body.validationQuestions || body.validation_questions || body.decisionQuestions || body.decision_questions || body.questionsToAnswer || body.questions_to_answer || body.followupQuestions || body.followup_questions || body.openQuestions || body.open_questions, sourceSection: 'questionsToSitWith' },
]);
const questionOptions = optionsFromQuestionsToSitWith(
questionSource.items,
questionSource.sourceSection || 'questionsToSitWith',
'Question to sit with'
);
if (buildOrderOptions.length) { if (buildOrderOptions.length) {
const proofLens = objectFrom(conceptMapLenses.question || conceptMapLenses.proof || conceptMapLenses.validation || conceptMapLenses.evidence); const proofLens = objectFrom(conceptMapLenses.question || conceptMapLenses.proof || conceptMapLenses.validation || conceptMapLenses.evidence);
const proofLensText = lensContent(conceptMapLenses.question) const proofLensText = lensContent(conceptMapLenses.question)
@@ -1663,6 +1675,7 @@ function optionsFromBody(body = {}) {
return normalizeCandidateGroup([ return normalizeCandidateGroup([
{ items: buildOrderOptions, sourceSection: 'concept-map.lenses.channel' }, { items: buildOrderOptions, sourceSection: 'concept-map.lenses.channel' },
...(proofOptions.length ? [{ items: proofOptions, sourceSection: 'concept-map.lenses.question', defaultLane: 'validate-next' }] : []), ...(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([ const actionThreadSource = firstArraySource([
@@ -1677,18 +1690,6 @@ function optionsFromBody(body = {}) {
actionThreadSource.sourceSection || 'threadsToHold', actionThreadSource.sourceSection || 'threadsToHold',
'Thread to hold' 'Thread to hold'
); );
const questionSource = firstArraySource([
{ items: conceptMap.questions_to_sit_with || conceptMap.questionsToSitWith || conceptMap.evidenceQuestions || conceptMap.evidence_questions || conceptMap.proofQuestions || conceptMap.proof_questions || conceptMap.validationQuestions || conceptMap.validation_questions || conceptMap.decisionQuestions || conceptMap.decision_questions || conceptMap.questionsToAnswer || conceptMap.questions_to_answer || conceptMap.followupQuestions || conceptMap.followup_questions || conceptMap.openQuestions || conceptMap.open_questions, sourceSection: 'concept-map.questionsToSitWith' },
{ items: snapshot.questions_to_sit_with || snapshot.questionsToSitWith || snapshot.evidenceQuestions || snapshot.evidence_questions || snapshot.proofQuestions || snapshot.proof_questions || snapshot.validationQuestions || snapshot.validation_questions || snapshot.decisionQuestions || snapshot.decision_questions || snapshot.questionsToAnswer || snapshot.questions_to_answer || snapshot.followupQuestions || snapshot.followup_questions || snapshot.openQuestions || snapshot.open_questions, sourceSection: 'snapshot.questionsToSitWith' },
{ items: envelope.questions_to_sit_with || envelope.questionsToSitWith || envelope.evidenceQuestions || envelope.evidence_questions || envelope.proofQuestions || envelope.proof_questions || envelope.validationQuestions || envelope.validation_questions || envelope.decisionQuestions || envelope.decision_questions || envelope.questionsToAnswer || envelope.questions_to_answer || envelope.followupQuestions || envelope.followup_questions || envelope.openQuestions || envelope.open_questions, sourceSection: 'ranker-input.questionsToSitWith' },
{ items: featureSet.questions_to_sit_with || featureSet.questionsToSitWith || featureSet.evidenceQuestions || featureSet.evidence_questions || featureSet.proofQuestions || featureSet.proof_questions || featureSet.validationQuestions || featureSet.validation_questions || featureSet.decisionQuestions || featureSet.decision_questions || featureSet.questionsToAnswer || featureSet.questions_to_answer || featureSet.followupQuestions || featureSet.followup_questions || featureSet.openQuestions || featureSet.open_questions, sourceSection: 'feature-set.questionsToSitWith' },
{ items: body.questions_to_sit_with || body.questionsToSitWith || body.evidenceQuestions || body.evidence_questions || body.proofQuestions || body.proof_questions || body.validationQuestions || body.validation_questions || body.decisionQuestions || body.decision_questions || body.questionsToAnswer || body.questions_to_answer || body.followupQuestions || body.followup_questions || body.openQuestions || body.open_questions, sourceSection: 'questionsToSitWith' },
]);
const questionOptions = optionsFromQuestionsToSitWith(
questionSource.items,
questionSource.sourceSection || 'questionsToSitWith',
'Question to sit with'
);
if (actionThreadOptions.length >= 2) return normalizeCandidateGroup([{ items: actionThreadOptions, sourceSection: actionThreadSource.sourceSection || 'threadsToHold' }]); if (actionThreadOptions.length >= 2) return normalizeCandidateGroup([{ items: actionThreadOptions, sourceSection: actionThreadSource.sourceSection || 'threadsToHold' }]);
if (actionThreadOptions.length === 1 && questionOptions.length) { if (actionThreadOptions.length === 1 && questionOptions.length) {
return normalizeCandidateGroup([ return normalizeCandidateGroup([