Accept game-specific Scattermind build fields

This commit is contained in:
OpenClaw Bot
2026-05-28 00:26:29 +02:00
parent 896198fe07
commit 6a2cc34759
4 changed files with 89 additions and 6 deletions
+50 -5
View File
@@ -692,6 +692,16 @@ function looksLikeRankPayload(value = {}) {
|| Array.isArray(value.riskiest_assumptions)
|| Array.isArray(value.risksToTest)
|| Array.isArray(value.risks_to_test)
|| Array.isArray(value.buildDecisions)
|| Array.isArray(value.build_decisions)
|| Array.isArray(value.explicitDeferrals)
|| Array.isArray(value.explicit_deferrals)
|| Array.isArray(value.playtestQuestions)
|| Array.isArray(value.playtest_questions)
|| Array.isArray(value.doNotLetThisBecome)
|| Array.isArray(value.do_not_let_this_become)
|| typeof value.doNotLetThisBecome === 'string'
|| typeof value.do_not_let_this_become === 'string'
);
}
@@ -1031,6 +1041,11 @@ function cleanDecisionContext(input = {}) {
...guardrailTextItems(envelope.threads_to_hold || envelope.threadsToHold || envelope.actionThreads || envelope.action_threads, 8),
...guardrailTextItems(featureSet.threads_to_hold || featureSet.threadsToHold || featureSet.actionThreads || featureSet.action_threads, 8),
...guardrailTextItems(input.threads_to_hold || input.threadsToHold || input.actionThreads || input.action_threads, 8),
...guardrailTextItems(conceptMap.doNotLetThisBecome || conceptMap.do_not_let_this_become, 8),
...guardrailTextItems(snapshot.doNotLetThisBecome || snapshot.do_not_let_this_become, 8),
...guardrailTextItems(envelope.doNotLetThisBecome || envelope.do_not_let_this_become, 8),
...guardrailTextItems(featureSet.doNotLetThisBecome || featureSet.do_not_let_this_become, 8),
...guardrailTextItems(input.doNotLetThisBecome || input.do_not_let_this_become, 8),
].filter(Boolean).join('\n'));
const ideaRoute = cleanText(input.ideaType || input.idea_type || input.category || input.route || envelope.ideaType || envelope.idea_type || featureSet.ideaType || featureSet.idea_type || artifact.ideaType || artifact.idea_type || conceptMap.ideaType || conceptMap.idea_type || snapshot.ideaType || snapshot.idea_type || inferIdeaRouteFromText([
input.idea,
@@ -1110,11 +1125,11 @@ function nonGoalConflicts(optionText, decisionContext = {}) {
function normalizeFeatureOption(item, index, fallbackId = 'feature', defaultSourceSection = '', defaultRecommendedLane = '') {
const rawValue = typeof item === 'string' || typeof item === 'number' ? String(item) : '';
const raw = rawValue ? { action: rawValue } : objectFrom(item);
const title = cleanText(raw.title || raw.name || raw.action || raw.move || raw.step || raw.task || raw.instruction || raw.nextMove || raw.next_move || raw.nextStep || raw.next_step || raw.recommendedNextStep || raw.recommended_next_step || raw.experiment || raw.testName || raw.test_name || raw.hypothesis || raw.label || raw.text || raw.content || raw.summary || '', 140);
const title = cleanText(raw.title || raw.name || raw.action || raw.move || raw.decision || raw.buildDecision || raw.build_decision || raw.step || raw.task || raw.instruction || raw.nextMove || raw.next_move || raw.nextStep || raw.next_step || raw.recommendedNextStep || raw.recommended_next_step || raw.experiment || raw.testName || raw.test_name || raw.hypothesis || raw.playtestQuestion || raw.playtest_question || raw.label || raw.text || raw.content || raw.summary || '', 140);
const proofGate = objectFrom(raw.proofGate || raw.proof_gate || raw.validationGate || raw.validation_gate || raw.evidenceGate || raw.evidence_gate || raw.decisionGate || raw.decision_gate || raw.gate);
const proofSteps = cleanTextList(raw.proofSteps || raw.proof_steps || raw.proof || raw.firstProof || raw.first_proof || raw.validationSteps || raw.validation_steps || raw.steps || raw.method || proofGate.steps || proofGate.proofSteps || proofGate.proof_steps || proofGate.method, 5, 180);
const dependencies = cleanTextList(raw.dependencies || raw.blockedBy || raw.blocked_by, 5, 120);
const evidenceNeeded = cleanText(raw.evidenceNeeded || raw.evidence_needed || raw.evidenceToCollect || raw.evidence_to_collect || raw.evidence || raw.test || raw.proofQuestion || raw.proof_question || raw.evidenceQuestion || raw.evidence_question || raw.questionToAnswer || raw.question_to_answer || raw.question || raw.learningGoal || raw.learning_goal || proofGate.evidenceNeeded || proofGate.evidence_needed || proofGate.evidence || proofGate.question || proofGate.evidenceQuestion || proofGate.evidence_question || proofGate.learningGoal || proofGate.learning_goal || '', 260);
const evidenceNeeded = cleanText(raw.evidenceNeeded || raw.evidence_needed || raw.evidenceToCollect || raw.evidence_to_collect || raw.evidence || raw.test || raw.playtestQuestion || raw.playtest_question || raw.proofQuestion || raw.proof_question || raw.evidenceQuestion || raw.evidence_question || raw.questionToAnswer || raw.question_to_answer || raw.question || raw.learningGoal || raw.learning_goal || proofGate.evidenceNeeded || proofGate.evidence_needed || proofGate.evidence || proofGate.question || proofGate.evidenceQuestion || proofGate.evidence_question || proofGate.learningGoal || proofGate.learning_goal || '', 260);
const userValue = cleanText(raw.userValue || raw.user_value || raw.value || raw.outcome || raw.why || raw.whyItMatters || raw.why_it_matters || raw.whyNow || raw.why_now, 260);
const risk = cleanText(raw.risk || raw.assumption || raw.unknown || raw.watchOut || raw.watch_out || proofGate.risk || proofGate.assumption || '', 220);
const nextStep = cleanText(raw.nextStep || raw.next_step || raw.nextAction || raw.next_action || raw.firstStep || raw.first_step || raw.manualStep || raw.manual_step || raw.actionToTake || raw.action_to_take || raw.firstProofStep || raw.first_proof_step || proofGate.nextStep || proofGate.next_step || proofGate.nextAction || proofGate.next_action || proofGate.firstStep || proofGate.first_step || proofGate.firstProofStep || proofGate.first_proof_step || raw.step || raw.task || raw.instruction || '', 260);
@@ -1188,8 +1203,8 @@ function candidateItems(value) {
const item = objectFrom(value);
if (!Object.keys(item).length) return [];
const hasCandidateShape = Boolean(
item.id || item.title || item.name || item.action || item.move || item.step || item.task || item.instruction ||
item.nextMove || item.next_move || item.nextStep || item.next_step || item.text || item.content || item.summary
item.id || item.title || item.name || item.action || item.move || item.decision || item.buildDecision || item.build_decision || item.step || item.task || item.instruction ||
item.nextMove || item.next_move || item.nextStep || item.next_step || item.playtestQuestion || item.playtest_question || item.text || item.content || item.summary
);
return hasCandidateShape ? [item] : [];
}
@@ -1212,7 +1227,17 @@ function buildOrderSectionGroup(buildOrder = {}, baseSection = 'buildOrder') {
function normalizeCandidateGroup(group = []) {
const options = group.flatMap(entry => {
const fallbackId = entry.sourceSection.toLowerCase().includes('action') ? 'action' : 'feature';
const fallbackId = entry.sourceSection.toLowerCase().includes('action')
? 'action'
: entry.sourceSection.toLowerCase().includes('deferral') || entry.sourceSection.toLowerCase().includes('defer')
? 'defer'
: entry.sourceSection.toLowerCase().includes('donotletthisbecome') || entry.sourceSection.toLowerCase().includes('do-not-let') || entry.sourceSection.toLowerCase().includes('park')
? 'park'
: entry.sourceSection.toLowerCase().includes('question') || entry.sourceSection.toLowerCase().includes('playtest')
? 'question'
: entry.sourceSection.toLowerCase().includes('decision')
? 'decision'
: 'feature';
return (entry.items || []).slice(0, 24).map((item, index) => normalizeFeatureOption(item, index, fallbackId, entry.sourceSection, entry.defaultLane));
}).filter(item => item.title).slice(0, 24);
return normalizeOptionIds(options);
@@ -1507,14 +1532,26 @@ function optionsFromBody(body = {}) {
{ items: body.validationTests || body.validation_tests || body.validationPlan || body.validation_plan, sourceSection: 'experiments', defaultLane: 'validate-next' },
{ items: body.proofTests || body.proof_tests || body.proofPlan || body.proof_plan, sourceSection: 'experiments', defaultLane: 'validate-next' },
{ items: body.assumptionTests || body.assumption_tests || body.riskiestAssumptions || body.riskiest_assumptions || body.risksToTest || body.risks_to_test, sourceSection: 'assumptionTests', defaultLane: 'validate-next' },
{ items: body.buildDecisions || body.build_decisions, sourceSection: 'buildDecisions', defaultLane: 'do-first' },
{ items: body.playtestQuestions || body.playtest_questions, sourceSection: 'playtestQuestions', defaultLane: 'validate-next' },
{ items: body.explicitDeferrals || body.explicit_deferrals, sourceSection: 'explicitDeferrals', defaultLane: 'defer' },
{ items: body.doNotLetThisBecome || body.do_not_let_this_become, sourceSection: 'doNotLetThisBecome', defaultLane: 'park' },
{ items: envelope.experiments, sourceSection: 'ranker-input.experiments', defaultLane: 'validate-next' },
{ items: envelope.validationTests || envelope.validation_tests || envelope.validationPlan || envelope.validation_plan, sourceSection: 'ranker-input.experiments', defaultLane: 'validate-next' },
{ items: envelope.proofTests || envelope.proof_tests || envelope.proofPlan || envelope.proof_plan, sourceSection: 'ranker-input.experiments', defaultLane: 'validate-next' },
{ items: envelope.assumptionTests || envelope.assumption_tests || envelope.riskiestAssumptions || envelope.riskiest_assumptions || envelope.risksToTest || envelope.risks_to_test, sourceSection: 'ranker-input.assumptionTests', defaultLane: 'validate-next' },
{ items: envelope.buildDecisions || envelope.build_decisions, sourceSection: 'ranker-input.buildDecisions', defaultLane: 'do-first' },
{ items: envelope.playtestQuestions || envelope.playtest_questions, sourceSection: 'ranker-input.playtestQuestions', defaultLane: 'validate-next' },
{ items: envelope.explicitDeferrals || envelope.explicit_deferrals, sourceSection: 'ranker-input.explicitDeferrals', defaultLane: 'defer' },
{ items: envelope.doNotLetThisBecome || envelope.do_not_let_this_become, sourceSection: 'ranker-input.doNotLetThisBecome', defaultLane: 'park' },
{ items: featureSet.experiments, sourceSection: 'feature-set.experiments', defaultLane: 'validate-next' },
{ items: featureSet.validationTests || featureSet.validation_tests || featureSet.validationPlan || featureSet.validation_plan, sourceSection: 'feature-set.experiments', defaultLane: 'validate-next' },
{ items: featureSet.proofTests || featureSet.proof_tests || featureSet.proofPlan || featureSet.proof_plan, sourceSection: 'feature-set.experiments', defaultLane: 'validate-next' },
{ items: featureSet.assumptionTests || featureSet.assumption_tests || featureSet.riskiestAssumptions || featureSet.riskiest_assumptions || featureSet.risksToTest || featureSet.risks_to_test, sourceSection: 'feature-set.assumptionTests', defaultLane: 'validate-next' },
{ items: featureSet.buildDecisions || featureSet.build_decisions, sourceSection: 'feature-set.buildDecisions', defaultLane: 'do-first' },
{ items: featureSet.playtestQuestions || featureSet.playtest_questions, sourceSection: 'feature-set.playtestQuestions', defaultLane: 'validate-next' },
{ items: featureSet.explicitDeferrals || featureSet.explicit_deferrals, sourceSection: 'feature-set.explicitDeferrals', defaultLane: 'defer' },
{ items: featureSet.doNotLetThisBecome || featureSet.do_not_let_this_become, sourceSection: 'feature-set.doNotLetThisBecome', defaultLane: 'park' },
{ items: body.validateNext || body.validate_next || body.validateManually || body.validate_manually || body.validate || body.validation || body.evidenceNext || body.evidence_next || body.tryNext || body.try_next || body.learnNext || body.learn_next || body.testManually || body.test_manually || body.manualProof || body.manual_proof, sourceSection: 'validateNext', defaultLane: 'validate-next' },
{ items: body.deferred || body.defer || body.later || body.afterProof || body.after_proof || body.holdForLater || body.hold_for_later || body.notYet || body.not_yet, sourceSection: 'deferred', defaultLane: 'defer' },
{ items: body.parkingLot || body.parking_lot || body.park || body.parked || body.probablyNoise || body.probably_noise || body.setAside || body.set_aside || body.outOfScope || body.out_of_scope, sourceSection: 'parkingLot', defaultLane: 'park' },
@@ -1539,6 +1576,10 @@ function optionsFromBody(body = {}) {
{ items: conceptMap.validationTests || conceptMap.validation_tests || conceptMap.validationPlan || conceptMap.validation_plan, sourceSection: 'concept-map.experiments', defaultLane: 'validate-next' },
{ items: conceptMap.proofTests || conceptMap.proof_tests || conceptMap.proofPlan || conceptMap.proof_plan, sourceSection: 'concept-map.experiments', defaultLane: 'validate-next' },
{ items: conceptMap.assumptionTests || conceptMap.assumption_tests || conceptMap.riskiestAssumptions || conceptMap.riskiest_assumptions || conceptMap.risksToTest || conceptMap.risks_to_test, sourceSection: 'concept-map.assumptionTests', defaultLane: 'validate-next' },
{ items: conceptMap.buildDecisions || conceptMap.build_decisions, sourceSection: 'concept-map.buildDecisions', defaultLane: 'do-first' },
{ items: conceptMap.playtestQuestions || conceptMap.playtest_questions, sourceSection: 'concept-map.playtestQuestions', defaultLane: 'validate-next' },
{ items: conceptMap.explicitDeferrals || conceptMap.explicit_deferrals, sourceSection: 'concept-map.explicitDeferrals', defaultLane: 'defer' },
{ items: conceptMap.doNotLetThisBecome || conceptMap.do_not_let_this_become, sourceSection: 'concept-map.doNotLetThisBecome', defaultLane: 'park' },
{ items: conceptMap.deferred || conceptMap.defer || conceptMap.later || conceptMap.afterProof || conceptMap.after_proof || conceptMap.holdForLater || conceptMap.hold_for_later || conceptMap.notYet || conceptMap.not_yet, sourceSection: 'concept-map.deferred', defaultLane: 'defer' },
{ items: conceptMap.parkingLot || conceptMap.parking_lot || conceptMap.park || conceptMap.parked || conceptMap.probablyNoise || conceptMap.probably_noise || conceptMap.setAside || conceptMap.set_aside || conceptMap.outOfScope || conceptMap.out_of_scope, sourceSection: 'concept-map.parkingLot', defaultLane: 'park' },
]);
@@ -1557,6 +1598,10 @@ function optionsFromBody(body = {}) {
{ items: snapshot.validationTests || snapshot.validation_tests || snapshot.validationPlan || snapshot.validation_plan, sourceSection: 'snapshot.experiments', defaultLane: 'validate-next' },
{ items: snapshot.proofTests || snapshot.proof_tests || snapshot.proofPlan || snapshot.proof_plan, sourceSection: 'snapshot.experiments', defaultLane: 'validate-next' },
{ items: snapshot.assumptionTests || snapshot.assumption_tests || snapshot.riskiestAssumptions || snapshot.riskiest_assumptions || snapshot.risksToTest || snapshot.risks_to_test, sourceSection: 'snapshot.assumptionTests', defaultLane: 'validate-next' },
{ items: snapshot.buildDecisions || snapshot.build_decisions, sourceSection: 'snapshot.buildDecisions', defaultLane: 'do-first' },
{ items: snapshot.playtestQuestions || snapshot.playtest_questions, sourceSection: 'snapshot.playtestQuestions', defaultLane: 'validate-next' },
{ items: snapshot.explicitDeferrals || snapshot.explicit_deferrals, sourceSection: 'snapshot.explicitDeferrals', defaultLane: 'defer' },
{ items: snapshot.doNotLetThisBecome || snapshot.do_not_let_this_become, sourceSection: 'snapshot.doNotLetThisBecome', defaultLane: 'park' },
{ items: snapshot.deferred || snapshot.defer || snapshot.later || snapshot.afterProof || snapshot.after_proof || snapshot.holdForLater || snapshot.hold_for_later || snapshot.notYet || snapshot.not_yet, sourceSection: 'snapshot.deferred', defaultLane: 'defer' },
{ items: snapshot.parkingLot || snapshot.parking_lot || snapshot.park || snapshot.parked || snapshot.probablyNoise || snapshot.probably_noise || snapshot.setAside || snapshot.set_aside || snapshot.outOfScope || snapshot.out_of_scope, sourceSection: 'snapshot.parkingLot', defaultLane: 'park' },
]);