Handle pasted Scattermind payload wrappers
This commit is contained in:
@@ -2153,6 +2153,42 @@ try {
|
|||||||
assert.equal(stringifiedRankerInput.handoff.readiness.status, 'ready');
|
assert.equal(stringifiedRankerInput.handoff.readiness.status, 'ready');
|
||||||
assert.deepEqual(stringifiedRankerInput.handoff.warnings, []);
|
assert.deepEqual(stringifiedRankerInput.handoff.warnings, []);
|
||||||
|
|
||||||
|
const proseWrappedPayloadEnvelopeResponse = await fetch(`${base}/api/rank-feedback`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
idea: `Here is the Scattermind handoff I copied from the reading page:\n\n${JSON.stringify({
|
||||||
|
payload: {
|
||||||
|
sourceName: 'Scattermind',
|
||||||
|
reference_code: 'SM-PROSE-PAYLOAD-NEXT-STEPS-1',
|
||||||
|
working_name: 'Prose-wrapped payload bridge',
|
||||||
|
ideaText: 'A tired user pasted a wrapper payload with next_steps instead of a pristine Ranker object.',
|
||||||
|
context: 'Manual proof first. Avoid saved workspace dashboards before one source-traced action works.',
|
||||||
|
next_steps: [
|
||||||
|
{ id: 'payload-next-step-active', action: 'Payload source-traced build-order active slice', why: 'Turn the payload-wrapped Scattermind handoff into one defended build order with provenance.', evidence_needed: 'Can a payload-wrapped next_steps export still produce one Do first action?', suggested_lane: 'do-first', source_item_id: 'payload-next-step-1', source_title: 'Payload next steps', ranker_hints: { value: 10, effort: 1, confidence: 9, urgency: 9, risk: 1 } },
|
||||||
|
{ id: 'payload-next-step-copy', action: 'Payload next-step copy brief', evidence_needed: 'Does the copied result keep source trace?', suggested_lane: 'validate-next', source_item_id: 'payload-next-step-2', source_title: 'Payload next steps' },
|
||||||
|
],
|
||||||
|
parking_lot: [
|
||||||
|
{ id: 'payload-next-step-dashboard', action: 'Payload next-step dashboard', evidence_needed: 'Not before proof.', source_item_id: 'payload-next-step-3', source_title: 'Payload next steps' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})}`,
|
||||||
|
mode: 'mvp',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
assert.equal(proseWrappedPayloadEnvelopeResponse.status, 200);
|
||||||
|
const proseWrappedPayloadEnvelope = await proseWrappedPayloadEnvelopeResponse.json();
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.input.embeddedPayloadSource, 'idea');
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.input.provenance.artifactId, 'SM-PROSE-PAYLOAD-NEXT-STEPS-1');
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.input.provenance.snapshotTitle, 'Prose-wrapped payload bridge');
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.input.optionCount, 3);
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.ranked[0].id, 'payload-next-step-active');
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.ranked[0].provenance.sourceSection, 'nextActions');
|
||||||
|
assert.ok(['do', 'test'].includes(proseWrappedPayloadEnvelope.ranked.find(item => item.id === 'payload-next-step-copy').lane.id));
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.ranked.find(item => item.id === 'payload-next-step-dashboard').lane.id, 'park');
|
||||||
|
assert.equal(proseWrappedPayloadEnvelope.handoff.readiness.status, 'ready');
|
||||||
|
assert.deepEqual(proseWrappedPayloadEnvelope.handoff.warnings, []);
|
||||||
|
|
||||||
const gameRouteGuardrailResponse = await fetch(`${base}/api/rank-feedback`, {
|
const gameRouteGuardrailResponse = await fetch(`${base}/api/rank-feedback`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
|||||||
@@ -587,6 +587,11 @@ function looksLikeRankPayload(value = {}) {
|
|||||||
|| value.concept_map_json
|
|| value.concept_map_json
|
||||||
|| value.buildOrderPreview
|
|| value.buildOrderPreview
|
||||||
|| value.build_order_preview
|
|| value.build_order_preview
|
||||||
|
|| value.payload
|
||||||
|
|| value.rankPayload
|
||||||
|
|| value.rank_payload
|
||||||
|
|| value.scattermindPayload
|
||||||
|
|| value.scattermind_payload
|
||||||
|| value.opening_reflection
|
|| value.opening_reflection
|
||||||
|| value.restated_idea
|
|| value.restated_idea
|
||||||
|| value.ideaText
|
|| value.ideaText
|
||||||
@@ -597,6 +602,10 @@ function looksLikeRankPayload(value = {}) {
|
|||||||
|| Array.isArray(value.recommended_actions)
|
|| Array.isArray(value.recommended_actions)
|
||||||
|| Array.isArray(value.suggestedActions)
|
|| Array.isArray(value.suggestedActions)
|
||||||
|| Array.isArray(value.suggested_actions)
|
|| Array.isArray(value.suggested_actions)
|
||||||
|
|| Array.isArray(value.nextSteps)
|
||||||
|
|| Array.isArray(value.next_steps)
|
||||||
|
|| Array.isArray(value.recommendedNextSteps)
|
||||||
|
|| Array.isArray(value.recommended_next_steps)
|
||||||
|| Array.isArray(value.nextActions)
|
|| Array.isArray(value.nextActions)
|
||||||
|| Array.isArray(value.next_actions)
|
|| Array.isArray(value.next_actions)
|
||||||
|| Array.isArray(value.next48Hours)
|
|| Array.isArray(value.next48Hours)
|
||||||
@@ -666,6 +675,24 @@ function looksLikeRankPayload(value = {}) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function payloadEnvelopeFrom(input = {}) {
|
||||||
|
const body = objectFrom(input);
|
||||||
|
return objectFrom(
|
||||||
|
body.payload
|
||||||
|
|| body.rankPayload
|
||||||
|
|| body.rank_payload
|
||||||
|
|| body.scattermindPayload
|
||||||
|
|| body.scattermind_payload
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unwrapPayloadEnvelope(input = {}) {
|
||||||
|
const body = objectFrom(input);
|
||||||
|
const payload = payloadEnvelopeFrom(body);
|
||||||
|
if (!Object.keys(payload).length || !looksLikeRankPayload(payload)) return body;
|
||||||
|
return { ...body, ...payload };
|
||||||
|
}
|
||||||
|
|
||||||
function extractFirstJsonObject(text = '') {
|
function extractFirstJsonObject(text = '') {
|
||||||
const start = text.indexOf('{');
|
const start = text.indexOf('{');
|
||||||
if (start < 0) return '';
|
if (start < 0) return '';
|
||||||
@@ -763,13 +790,14 @@ function expandEmbeddedRankPayload(body = {}) {
|
|||||||
? original[key]
|
? original[key]
|
||||||
: null;
|
: null;
|
||||||
if (!embedded) continue;
|
if (!embedded) continue;
|
||||||
|
const unwrappedEmbedded = unwrapPayloadEnvelope(embedded);
|
||||||
const expanded = stringOnlyEmbeddedKeys.has(key)
|
const expanded = stringOnlyEmbeddedKeys.has(key)
|
||||||
? { ...original, [key]: embedded }
|
? { ...original, [key]: unwrappedEmbedded }
|
||||||
: { ...original, ...embedded };
|
: { ...original, ...unwrappedEmbedded };
|
||||||
if (key === 'idea' && !embedded.idea && !embedded.ideaText) expanded.idea = '';
|
if (key === 'idea' && !unwrappedEmbedded.idea && !unwrappedEmbedded.ideaText) expanded.idea = '';
|
||||||
if (key === 'optionsText' && !embedded.optionsText) expanded.optionsText = '';
|
if (key === 'optionsText' && !unwrappedEmbedded.optionsText) expanded.optionsText = '';
|
||||||
if (original.mode && !embedded.mode) expanded.mode = original.mode;
|
if (original.mode && !unwrappedEmbedded.mode) expanded.mode = original.mode;
|
||||||
if (original.context && !embedded.context) expanded.context = original.context;
|
if (original.context && !unwrappedEmbedded.context) expanded.context = original.context;
|
||||||
expanded._embeddedPayloadSource = key;
|
expanded._embeddedPayloadSource = key;
|
||||||
return expanded;
|
return expanded;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user