Accept laned Scattermind build order objects

This commit is contained in:
OpenClaw Bot
2026-05-27 00:24:02 +02:00
parent 4b3fb9e7d9
commit 428e9c337f
3 changed files with 76 additions and 14 deletions
+30 -13
View File
@@ -640,16 +640,17 @@ function nonGoalConflicts(optionText, decisionContext = {}) {
}
function normalizeFeatureOption(item, index, fallbackId = 'feature', defaultSourceSection = '', defaultRecommendedLane = '') {
const title = cleanText(item?.title || item?.name || item?.action || '', 140);
const proofSteps = cleanTextList(item?.proofSteps || item?.proof || item?.validationSteps, 5, 180);
const dependencies = cleanTextList(item?.dependencies || item?.blockedBy, 5, 120);
const evidenceNeeded = cleanText(item?.evidenceNeeded || item?.evidence || item?.test || '', 260);
const userValue = cleanText(item?.userValue || item?.value || item?.outcome || item?.why, 260);
const risk = cleanText(item?.risk || item?.assumption || item?.unknown || '', 220);
const sourceSection = cleanText(item?.sourceSection || item?.section || item?.lane || item?.origin || defaultSourceSection, 80);
const recommendedLane = cleanText(item?.recommendedLane || item?.laneHint || item?.suggestedLane || defaultRecommendedLane || '', 40).toLowerCase();
const raw = typeof item === 'string' || typeof item === 'number' ? { action: String(item) } : objectFrom(item);
const title = cleanText(raw.title || raw.name || raw.action || raw.move || raw.label || '', 140);
const proofSteps = cleanTextList(raw.proofSteps || raw.proof || raw.validationSteps, 5, 180);
const dependencies = cleanTextList(raw.dependencies || raw.blockedBy, 5, 120);
const evidenceNeeded = cleanText(raw.evidenceNeeded || raw.evidence || raw.test || raw.evidenceQuestion || raw.questionToAnswer || '', 260);
const userValue = cleanText(raw.userValue || raw.value || raw.outcome || raw.why, 260);
const risk = cleanText(raw.risk || raw.assumption || raw.unknown || '', 220);
const sourceSection = cleanText(raw.sourceSection || raw.section || raw.lane || raw.origin || defaultSourceSection, 80);
const recommendedLane = cleanText(raw.recommendedLane || raw.laneHint || raw.suggestedLane || defaultRecommendedLane || '', 40).toLowerCase();
const descriptionParts = [
item?.description || item?.brief || '',
raw.description || raw.brief || '',
userValue && `User value: ${userValue}`,
evidenceNeeded && `Evidence needed: ${evidenceNeeded}`,
risk && `Risk: ${risk}`,
@@ -657,12 +658,12 @@ function normalizeFeatureOption(item, index, fallbackId = 'feature', defaultSour
dependencies.length && `Dependencies: ${dependencies.join(', ')}`,
].filter(Boolean);
return {
id: cleanText(item?.id || item?.key || `${fallbackId}-${index + 1}`, 80) || `${fallbackId}-${index + 1}`,
id: cleanText(raw.id || raw.key || `${fallbackId}-${index + 1}`, 80) || `${fallbackId}-${index + 1}`,
title,
description: cleanText(descriptionParts.join(' '), 760),
factors: { userValue, evidenceNeeded, risk, proofSteps, dependencies, recommendedLane, metricHints: cleanMetricHints(item) },
factors: { userValue, evidenceNeeded, risk, proofSteps, dependencies, recommendedLane, metricHints: cleanMetricHints(raw) },
provenance: {
sourceId: cleanText(item?.sourceId || item?.sourceArtifactId || item?.id || '', 120),
sourceId: cleanText(raw.sourceId || raw.sourceArtifactId || raw.id || '', 120),
sourceSection,
},
};
@@ -691,6 +692,16 @@ function compactCandidateGroup(group = []) {
return group.filter(entry => Array.isArray(entry?.items) && entry.items.length > 0);
}
function buildOrderSectionGroup(buildOrder = {}, baseSection = 'buildOrder') {
const source = objectFrom(buildOrder);
return compactCandidateGroup([
{ items: source.doFirst || source.do_first || source.buildFirst || source.buildNow || source.now, sourceSection: `${baseSection}.doFirst`, defaultLane: 'do-first' },
{ items: source.validateNext || source.validate_next || source.testNext || source.testManually || source.validation, sourceSection: `${baseSection}.validateNext`, defaultLane: 'validate-next' },
{ items: source.defer || source.deferred || source.later || source.afterProof, sourceSection: `${baseSection}.defer`, defaultLane: 'defer' },
{ items: source.park || source.parkingLot || source.parked || source.probablyNoise || source.noise, sourceSection: `${baseSection}.park`, defaultLane: 'park' },
]);
}
function normalizeCandidateGroup(group = []) {
const options = group.flatMap(entry => {
const fallbackId = entry.sourceSection.toLowerCase().includes('action') ? 'action' : 'feature';
@@ -766,7 +777,13 @@ function optionsFromBody(body = {}) {
{ items: conceptMap.deferred || conceptMap.defer || conceptMap.later, sourceSection: 'concept-map.deferred', defaultLane: 'defer' },
{ items: conceptMap.parkingLot || conceptMap.park || conceptMap.parked, sourceSection: 'concept-map.parkingLot', defaultLane: 'park' },
]);
const groupedCandidates = [...directCandidateGroup, ...conceptMapCandidateGroup];
const groupedCandidates = [
...directCandidateGroup,
...conceptMapCandidateGroup,
...buildOrderSectionGroup(body.buildOrder, 'buildOrder'),
...buildOrderSectionGroup(featureSet.buildOrder, 'feature-set.buildOrder'),
...buildOrderSectionGroup(conceptMap.buildOrder, 'concept-map.buildOrder'),
];
if (groupedCandidates.length) return normalizeCandidateGroup(groupedCandidates);
const buildOrderText = lensContent(conceptMapLenses.channel)
|| lensContent(conceptMapLenses.buildOrder)