From dc75206fcd134762158e379b931aae5569455be3 Mon Sep 17 00:00:00 2001 From: OpenClaw Bot Date: Wed, 27 May 2026 19:18:45 +0200 Subject: [PATCH] Accept paid Concept Map build-order labels --- scripts/check-rank-feedback.mjs | 30 ++++++++++++++++++++++++++++++ server.js | 8 ++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/scripts/check-rank-feedback.mjs b/scripts/check-rank-feedback.mjs index 2c62e13..1a3fea1 100644 --- a/scripts/check-rank-feedback.mjs +++ b/scripts/check-rank-feedback.mjs @@ -266,6 +266,36 @@ try { assert.match(softDashLabel.handoff.itemTrace.find(item => item.id === 'build-order-1').sourceQuote, /Continue first/); assert.deepEqual(softDashLabel.handoff.warnings, []); + const paidLabelResponse = await fetch(`${base}/api/rank-feedback`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + sourceName: 'Scattermind', + artifactId: 'concept_map_paid_label_aliases', + originalPrompt: 'Scattermind paid Concept Map used decisive paid-output wording from the current prompt.', + context: 'Solo builder. Manual proof first. Avoid account dashboards and billing until evidence exists.', + conceptMap: { + working_name: 'Paid label aliases', + lenses: { + channel: { + title: 'Build Order', + content: 'Ship this first — Manual source-traced build order preview from one Concept Map. Test first — Ask 3 tired users which step they would take. Leave out — Account dashboard and saved workspace. Skip for now — Subscription billing and admin controls.', + }, + }, + }, + }), + }); + assert.equal(paidLabelResponse.status, 200); + const paidLabel = await paidLabelResponse.json(); + assert.equal(paidLabel.input.optionCount, 4); + assert.equal(paidLabel.buildOrder.doFirst[0], 'build-order-1', 'paid Scattermind label aliases should still produce an active build slice'); + assert.equal(paidLabel.ranked.find(item => item.id === 'build-order-1').lane.id, 'do'); + assert.equal(paidLabel.ranked.find(item => item.id === 'build-order-2').lane.id, 'test'); + assert.equal(paidLabel.ranked.find(item => item.id === 'build-order-3').lane.id, 'defer'); + assert.equal(paidLabel.ranked.find(item => item.id === 'build-order-4').lane.id, 'defer'); + assert.match(paidLabel.brief.decisionReceipt.sourceAnchor, /concept-map\.lenses\.channel/); + assert.deepEqual(paidLabel.handoff.warnings, []); + const hintedResponse = await fetch(`${base}/api/rank-feedback`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, diff --git a/server.js b/server.js index 60e1156..b6aeb59 100644 --- a/server.js +++ b/server.js @@ -1055,7 +1055,7 @@ function normalizeCandidateGroup(group = []) { } const buildOrderLabelSeparator = '\\s*(?::|[-–—])\\s*'; -const buildOrderLabelPattern = '(build first|start here|ship first|first week|week one|first-week build order|continue first|make tangible first|make tangible|try next|evidence next|learn next|test manually|validate next|hold for later|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 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'); function sentenceFragments(text = '') { @@ -1073,9 +1073,9 @@ function titleFromBuildOrderFragment(value = '') { } function laneFromBuildOrderLabel(fragment = '') { - if (new RegExp(`^(build first|start here|ship first|first week|week one|first-week build order|continue first|make tangible first|make tangible)${buildOrderLabelSeparator}`, 'i').test(fragment)) return 'do-first'; - if (new RegExp(`^(try next|evidence next|learn next|test manually|validate next)${buildOrderLabelSeparator}`, 'i').test(fragment)) return 'validate-next'; - if (new RegExp(`^(hold for later|not yet|defer|do not build yet|don't build yet)${buildOrderLabelSeparator}`, 'i').test(fragment)) return 'defer'; + if (new RegExp(`^(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)${buildOrderLabelSeparator}`, 'i').test(fragment)) return 'do-first'; + if (new RegExp(`^(try next|test first|prove first|evidence next|learn next|test manually|validate next)${buildOrderLabelSeparator}`, 'i').test(fragment)) return 'validate-next'; + if (new RegExp(`^(hold for later|leave out|skip for now|not yet|defer|do not build yet|don't build yet)${buildOrderLabelSeparator}`, 'i').test(fragment)) return 'defer'; if (new RegExp(`^(set aside|out of scope|probably noise|park)${buildOrderLabelSeparator}`, 'i').test(fragment)) return 'park'; return ''; }