Accept softer Scattermind continuation aliases

This commit is contained in:
OpenClaw Bot
2026-05-27 18:37:07 +02:00
parent c3edf9f29d
commit ec27d13330
4 changed files with 99 additions and 5 deletions
+1 -1
View File
@@ -51,7 +51,7 @@ Candidate items may include optional 110 `rankerHints` (`value`, `effort`, `c
Candidate trace note: candidate-level `sourceItemId` / `traceId`, `sourceTitle` / `lensTitle`, and `sourceExcerpt` / `sourceQuote` are preserved in ranked items, `buildOrderDetails`, and `handoff.itemTrace`. Lens-only Build Order text is also split into deterministic `concept-map.lenses.channel#N` source IDs with the original labelled sentence carried as `sourceQuote`, so pasted paid Concept Maps remain traceable even without explicit candidate objects. String items in laned Build Order arrays now also receive deterministic section-local source IDs such as `concept-map.buildOrder.validateNext#1` and carry the original string as `sourceQuote`, so simple Scattermind exports stay addressable downstream instead of becoming anonymous `feature-1` rows. Ranker also accepts the current Scattermind storage-row shape with `referenceCode`, `ideaText`, `context`, and string-valued `fullReadingJson` / `full_reading_json`; it expands the saved paid Concept Map before ranking so operators do not have to hand-copy lenses out of Appwrite rows. If the row only has free Snapshot data (`glimpseJson` / `glimpse_json` / `snapshotJson`), Ranker expands that Snapshot into a minimal continuation order: one manual proof plus the first evidence question, with the Snapshot reference code/title preserved for provenance. The public paste form mirrors this: a prose-wrapped/fenced Appwrite row paste stays intact for the API instead of unwrapping the stringified reading into nonsense fields. The decision `brief.quickGlance.sourceTrace` now repeats the winning item's source section/id/title/quote, and both `brief.source.originalPromptExcerpt` / `handoff.source.originalPromptExcerpt` or, when the original prompt is unavailable, `sourceSummaryExcerpt` carry the source context so a downstream Scattermind handoff can show why the build order exists without digging through `input.provenance`. Scattermind should use these when a next move came from a specific Concept Map lens sentence, so Ranker can defend not just what wins but where the judgement came from. Candidate trace note: candidate-level `sourceItemId` / `traceId`, `sourceTitle` / `lensTitle`, and `sourceExcerpt` / `sourceQuote` are preserved in ranked items, `buildOrderDetails`, and `handoff.itemTrace`. Lens-only Build Order text is also split into deterministic `concept-map.lenses.channel#N` source IDs with the original labelled sentence carried as `sourceQuote`, so pasted paid Concept Maps remain traceable even without explicit candidate objects. String items in laned Build Order arrays now also receive deterministic section-local source IDs such as `concept-map.buildOrder.validateNext#1` and carry the original string as `sourceQuote`, so simple Scattermind exports stay addressable downstream instead of becoming anonymous `feature-1` rows. Ranker also accepts the current Scattermind storage-row shape with `referenceCode`, `ideaText`, `context`, and string-valued `fullReadingJson` / `full_reading_json`; it expands the saved paid Concept Map before ranking so operators do not have to hand-copy lenses out of Appwrite rows. If the row only has free Snapshot data (`glimpseJson` / `glimpse_json` / `snapshotJson`), Ranker expands that Snapshot into a minimal continuation order: one manual proof plus the first evidence question, with the Snapshot reference code/title preserved for provenance. The public paste form mirrors this: a prose-wrapped/fenced Appwrite row paste stays intact for the API instead of unwrapping the stringified reading into nonsense fields. The decision `brief.quickGlance.sourceTrace` now repeats the winning item's source section/id/title/quote, and both `brief.source.originalPromptExcerpt` / `handoff.source.originalPromptExcerpt` or, when the original prompt is unavailable, `sourceSummaryExcerpt` carry the source context so a downstream Scattermind handoff can show why the build order exists without digging through `input.provenance`. Scattermind should use these when a next move came from a specific Concept Map lens sentence, so Ranker can defend not just what wins but where the judgement came from.
Soft Scattermind labels are accepted at the bridge boundary so Scattermind does not need to use harsh verdict copy in its own product surface. Lens text can say `Continue first`, `Make tangible`, `Try next`, `Evidence next`, `Hold for later`, or `Set aside`; Build Order objects and direct bridge/envelope sections can use matching camel/snake-case keys such as `continueFirst`, `evidenceNext`, `holdForLater`, and `setAside`. Ranker maps those to `doFirst / validateNext / defer / park` while preserving the softer original label in `sourceQuote` or candidate source trace. Soft Scattermind labels are accepted at the bridge boundary so Scattermind does not need to use harsh verdict copy in its own product surface. Lens text can say `Continue first`, `Make tangible`, `Try next`, `Evidence next`, `Hold for later`, or `Set aside`; Build Order objects and direct bridge/envelope sections can use matching camel/snake-case keys such as `continueFirst`, `evidenceNext`, `holdForLater`, and `setAside`. Ranker maps those to `doFirst / validateNext / defer / park` while preserving the softer original label in `sourceQuote` or candidate source trace. Ranker also accepts softer continuation envelopes named `rankerBridge`, `continuation`, or `continuationPlan`, candidate arrays named `possibleNextMoves`, `suggestedNextMoves`, `recommendations`, or `opportunities`, and laned `buildOrderPreview` / `build_order_preview` objects so Scattermind can pass a paid Concept Map preview without renaming it into software-feature language.
Lane safety note: explicit Scattermind `defer` / `park` hints are hard rails, not mild suggestions. Source `nonGoals` / `avoid` guardrails are also hard enough to keep conflicting candidates out of Do first / Validate next even when their local scoring hints look attractive; soft guardrail language such as “this is not a dashboard” or “keep auth/billing/workspaces out until proof” is promoted into non-goals, not merely background context. The result will mark the lane source as `source-non-goal` so the handoff can explain that the candidate needs guardrail resolution before active work. Handoff `source.requiresSourceTrace` is true only when a real source artifact/title is present; plain idea-only ranking still warns about a missing artifact ID when it carries prompt provenance, but it does not spam source-section/evidence warnings meant for Scattermind artifacts. Handoff `readiness` now gives downstream bridge consumers a deterministic gate: `ready`, `usable-with-warnings`, `needs-source-context`, or `blocked`, with blockers and next checks for missing evidence, source trace, duplicate IDs, or active source-non-goal conflicts. Handoff `activeSlice` (`ranker-active-slice-v1`) is the compact machine-readable continuation unit: one active item, its proof/evidence/success/kill signals, source anchor, held-back items, readiness status, and the rule that only this slice is build-ready. For tired first-screen users, `brief.decisionReceipt` repeats the one active move, first proof step, evidence question, held-back items, source anchor, and the handoff rule that only Do first is active; use it as the compact result strip before showing the full lane board. For low-friction handoff, `/api/rank-feedback` also detects a raw Scattermind/Concept Map JSON object pasted into `idea`, `ideaText`, `optionsText`, or wrapper keys such as `payload`; it expands that object before ranking and reports `input.embeddedPayloadSource` so the public form can accept copy/paste exports without a custom import screen. Exact free Snapshot JSON (`working_name`, `restated_idea`, `lenses.shape`, `questions_to_sit_with`, `reference_code`) is rankable too: Ranker derives a manual proof active slice plus evidence questions, carrying the Snapshot reference code/title into provenance so a Snapshot-only handoff does not need a paid Concept Map before it can produce a useful build order. If a Concept Map only carries `questions_to_sit_with` / `questionsToSitWith` / `openQuestions` and no explicit build-order lanes or action threads, Ranker converts those questions into Validate-next evidence actions with source trace instead of pretending they are software features. Lane safety note: explicit Scattermind `defer` / `park` hints are hard rails, not mild suggestions. Source `nonGoals` / `avoid` guardrails are also hard enough to keep conflicting candidates out of Do first / Validate next even when their local scoring hints look attractive; soft guardrail language such as “this is not a dashboard” or “keep auth/billing/workspaces out until proof” is promoted into non-goals, not merely background context. The result will mark the lane source as `source-non-goal` so the handoff can explain that the candidate needs guardrail resolution before active work. Handoff `source.requiresSourceTrace` is true only when a real source artifact/title is present; plain idea-only ranking still warns about a missing artifact ID when it carries prompt provenance, but it does not spam source-section/evidence warnings meant for Scattermind artifacts. Handoff `readiness` now gives downstream bridge consumers a deterministic gate: `ready`, `usable-with-warnings`, `needs-source-context`, or `blocked`, with blockers and next checks for missing evidence, source trace, duplicate IDs, or active source-non-goal conflicts. Handoff `activeSlice` (`ranker-active-slice-v1`) is the compact machine-readable continuation unit: one active item, its proof/evidence/success/kill signals, source anchor, held-back items, readiness status, and the rule that only this slice is build-ready. For tired first-screen users, `brief.decisionReceipt` repeats the one active move, first proof step, evidence question, held-back items, source anchor, and the handoff rule that only Do first is active; use it as the compact result strip before showing the full lane board. For low-friction handoff, `/api/rank-feedback` also detects a raw Scattermind/Concept Map JSON object pasted into `idea`, `ideaText`, `optionsText`, or wrapper keys such as `payload`; it expands that object before ranking and reports `input.embeddedPayloadSource` so the public form can accept copy/paste exports without a custom import screen. Exact free Snapshot JSON (`working_name`, `restated_idea`, `lenses.shape`, `questions_to_sit_with`, `reference_code`) is rankable too: Ranker derives a manual proof active slice plus evidence questions, carrying the Snapshot reference code/title into provenance so a Snapshot-only handoff does not need a paid Concept Map before it can produce a useful build order. If a Concept Map only carries `questions_to_sit_with` / `questionsToSitWith` / `openQuestions` and no explicit build-order lanes or action threads, Ranker converts those questions into Validate-next evidence actions with source trace instead of pretending they are software features.
+5 -3
View File
@@ -63,9 +63,9 @@ function parsePastedJsonPayload(value) {
const looksLikeBridgePayload = parsed && typeof parsed === 'object' && !Array.isArray(parsed) && ( const looksLikeBridgePayload = parsed && typeof parsed === 'object' && !Array.isArray(parsed) && (
parsed.schema || parsed.featureSet || parsed.feature_set || parsed.candidateSet || parsed.candidate_set || parsed.candidateFeatureSet || parsed.candidate_feature_set || parsed.rankReadyFeatureSet || parsed.rank_ready_feature_set parsed.schema || parsed.featureSet || parsed.feature_set || parsed.candidateSet || parsed.candidate_set || parsed.candidateFeatureSet || parsed.candidate_feature_set || parsed.rankReadyFeatureSet || parsed.rank_ready_feature_set
|| parsed.snapshot || parsed.conceptMap || parsed.concept_map || parsed.buildOrder || parsed.build_order || parsed.lenses || parsed.snapshot || parsed.conceptMap || parsed.concept_map || parsed.buildOrder || parsed.build_order || parsed.lenses
|| parsed.payload || parsed.rankPayload || parsed.scattermindPayload || parsed.conceptMapJson || parsed.rankerInput || parsed.ranker_input || parsed.rankerHandoff || parsed.ranker_handoff || parsed.rankReady || parsed.rank_ready || parsed.bridge || parsed.bridgePayload || parsed.bridge_payload || parsed.payload || parsed.rankPayload || parsed.scattermindPayload || parsed.conceptMapJson || parsed.rankerInput || parsed.ranker_input || parsed.rankerHandoff || parsed.ranker_handoff || parsed.rankerBridge || parsed.ranker_bridge || parsed.rankReady || parsed.rank_ready || parsed.bridge || parsed.bridgePayload || parsed.bridge_payload || parsed.continuation || parsed.continuationPlan || parsed.continuation_plan
|| parsed.concept_map_json || parsed.fullReadingJson || parsed.full_reading_json || parsed.fullReading || parsed.full_reading || parsed.concept_map_json || parsed.fullReadingJson || parsed.full_reading_json || parsed.fullReading || parsed.full_reading
|| parsed.glimpseJson || parsed.glimpse_json || parsed.snapshotJson || parsed.snapshot_json || parsed.glimpseJson || parsed.glimpse_json || parsed.snapshotJson || parsed.snapshot_json || parsed.buildOrderPreview || parsed.build_order_preview
|| parsed.reference_code || parsed.referenceCode || parsed.artifactId || parsed.sourceArtifactId || parsed.source_artifact_id || parsed.reference_code || parsed.referenceCode || parsed.artifactId || parsed.sourceArtifactId || parsed.source_artifact_id
|| parsed.ideaText || parsed.idea_text || parsed.originalPrompt || parsed.original_prompt || parsed.sourceSummary || parsed.source_summary || parsed.opening_reflection || parsed.restated_idea || parsed.ideaText || parsed.idea_text || parsed.originalPrompt || parsed.original_prompt || parsed.sourceSummary || parsed.source_summary || parsed.opening_reflection || parsed.restated_idea
|| Array.isArray(parsed.features) || Array.isArray(parsed.actions) || Array.isArray(parsed.candidates) || Array.isArray(parsed.features) || Array.isArray(parsed.actions) || Array.isArray(parsed.candidates)
@@ -73,6 +73,8 @@ function parsePastedJsonPayload(value) {
|| Array.isArray(parsed.rankReadyActions) || Array.isArray(parsed.rank_ready_actions) || Array.isArray(parsed.rankReadyActions) || Array.isArray(parsed.rank_ready_actions)
|| Array.isArray(parsed.recommendedActions) || Array.isArray(parsed.recommended_actions) || Array.isArray(parsed.suggestedActions) || Array.isArray(parsed.suggested_actions) || Array.isArray(parsed.recommendedActions) || Array.isArray(parsed.recommended_actions) || Array.isArray(parsed.suggestedActions) || Array.isArray(parsed.suggested_actions)
|| Array.isArray(parsed.nextActions) || Array.isArray(parsed.next_actions) || Array.isArray(parsed.nextMoves) || Array.isArray(parsed.next_moves) || Array.isArray(parsed.nextActions) || Array.isArray(parsed.next_actions) || Array.isArray(parsed.nextMoves) || Array.isArray(parsed.next_moves)
|| Array.isArray(parsed.possibleNextMoves) || Array.isArray(parsed.possible_next_moves) || Array.isArray(parsed.suggestedNextMoves) || Array.isArray(parsed.suggested_next_moves)
|| Array.isArray(parsed.recommendations) || Array.isArray(parsed.opportunities)
|| Array.isArray(parsed.doFirst) || Array.isArray(parsed.do_first) || Array.isArray(parsed.continueFirst) || Array.isArray(parsed.continue_first) || Array.isArray(parsed.makeTangible) || Array.isArray(parsed.make_tangible) || Array.isArray(parsed.doFirst) || Array.isArray(parsed.do_first) || Array.isArray(parsed.continueFirst) || Array.isArray(parsed.continue_first) || Array.isArray(parsed.makeTangible) || Array.isArray(parsed.make_tangible)
|| Array.isArray(parsed.validateNext) || Array.isArray(parsed.validate_next) || Array.isArray(parsed.evidenceNext) || Array.isArray(parsed.evidence_next) || Array.isArray(parsed.tryNext) || Array.isArray(parsed.try_next) || Array.isArray(parsed.validateNext) || Array.isArray(parsed.validate_next) || Array.isArray(parsed.evidenceNext) || Array.isArray(parsed.evidence_next) || Array.isArray(parsed.tryNext) || Array.isArray(parsed.try_next)
|| Array.isArray(parsed.deferred) || Array.isArray(parsed.holdForLater) || Array.isArray(parsed.hold_for_later) || Array.isArray(parsed.deferred) || Array.isArray(parsed.holdForLater) || Array.isArray(parsed.hold_for_later)
@@ -121,7 +123,7 @@ function payloadFromForm(formPayload) {
const optionsJson = parsePastedJsonPayload(formPayload.optionsText); const optionsJson = parsePastedJsonPayload(formPayload.optionsText);
const embedded = ideaJson || optionsJson; const embedded = ideaJson || optionsJson;
if (!embedded) return formPayload; if (!embedded) return formPayload;
const unwrapCandidate = embedded.payload || embedded.rankPayload || embedded.scattermindPayload || embedded; const unwrapCandidate = embedded.payload || embedded.rankPayload || embedded.scattermindPayload || embedded.rankerBridge || embedded.ranker_bridge || embedded.continuation || embedded.continuationPlan || embedded.continuation_plan || embedded;
const unwrapped = unwrapCandidate && typeof unwrapCandidate === 'object' && !Array.isArray(unwrapCandidate) ? unwrapCandidate : embedded; const unwrapped = unwrapCandidate && typeof unwrapCandidate === 'object' && !Array.isArray(unwrapCandidate) ? unwrapCandidate : embedded;
const merged = { ...unwrapped }; const merged = { ...unwrapped };
if (!merged.mode && formPayload.mode) merged.mode = formPayload.mode; if (!merged.mode && formPayload.mode) merged.mode = formPayload.mode;
+61 -1
View File
@@ -1573,7 +1573,67 @@ try {
assert.equal(rankReadyActionsEnvelope.handoff.readiness.status, 'ready'); assert.equal(rankReadyActionsEnvelope.handoff.readiness.status, 'ready');
assert.deepEqual(rankReadyActionsEnvelope.handoff.warnings, []); assert.deepEqual(rankReadyActionsEnvelope.handoff.warnings, []);
console.log(JSON.stringify({ ok: true, top: data.ranked[0].id, hintedTop: hinted.ranked[0].id, actionTop: actions.ranked[0].id, nestedConceptTop: nestedConcept.ranked[0].id, nonGoalTop: nonGoal.ranked[0].id, structuredContextTop: structuredContext.ranked[0].id, lensOnlyTop: lensOnly.ranked[0].id, scattermindPaidShapeTop: scattermindPaidShape.ranked[0].id, mergedContextTop: mergedContext.ranked[0].id, embeddedJsonTop: embeddedJson.ranked[0].id, fencedJsonTop: fencedJson.ranked[0].id, embeddedSnapshotTop: embeddedSnapshot.ranked[0].id, sourceExcerptTop: sourceExcerpt.ranked[0].id, snakeCaseBridgeTop: snakeCaseBridge.ranked[0].id, nextStepsAliasTop: nextStepsAlias.ranked[0].id, summaryGuardrailTop: summaryGuardrail.ranked[0].id, bridgeEnvelopeTop: bridgeEnvelope.ranked[0].id, directEnvelopeSectionsTop: directEnvelopeSections.ranked[0].id, softDirectLaneAliasesTop: softDirectLaneAliases.ranked[0].id, threadsFallbackTop: threadsFallback.ranked[0].id, questionsFallbackTop: questionsFallback.ranked[0].id, freeSnapshotTop: freeSnapshot.ranked[0].id, storedScattermindRowTop: storedScattermindRow.ranked[0].id, candidateActionsAliasTop: candidateActionsAlias.ranked[0].id, rankReadyActionsEnvelopeTop: rankReadyActionsEnvelope.ranked[0].id, duplicateIds: duplicateIds.ranked.map(item => item.id), readiness: data.handoff.readiness.status, provenance: data.input.provenance, buildOrder: data.buildOrder }, null, 2)); const continuationEnvelopeResponse = await fetch(`${base}/api/rank-feedback`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sourceName: 'Scattermind',
continuationPlan: {
reference_code: 'SM-CONTINUATION-ALIASES-1',
working_name: 'Continuation alias bridge',
ideaText: 'Scattermind exported softer continuation language rather than a formal feature set.',
context: 'Solo builder. Keep this out of workspace/dashboard/billing land until one manual proof works.',
possible_next_moves: [
{ id: 'possible-manual-proof', action: 'Possible manual proof card', why: 'Turn the Concept Map into one active proof card with source trace.', evidence_needed: 'Can one tired user say what to do first?', suggested_lane: 'do-first', source_item_id: 'possible-move-1', source_title: 'Possible next moves', ranker_hints: { value: 9, effort: 2, confidence: 8, urgency: 8, risk: 2 } },
{ id: 'possible-copy-brief', action: 'Possible copyable handoff', why: 'Let the user carry the defended order into notes.', evidence_needed: 'Does the copied handoff preserve the active move?', suggested_lane: 'validate-next', source_item_id: 'possible-move-2', source_title: 'Possible next moves' },
{ id: 'possible-dashboard', action: 'Possible saved dashboard', why: 'Saved workspace dashboard with accounts, billing, and collaboration.', suggested_lane: 'park', source_item_id: 'possible-move-3', source_title: 'Possible next moves' },
],
},
}),
});
assert.equal(continuationEnvelopeResponse.status, 200);
const continuationEnvelope = await continuationEnvelopeResponse.json();
assert.equal(continuationEnvelope.input.provenance.artifactId, 'SM-CONTINUATION-ALIASES-1');
assert.equal(continuationEnvelope.input.provenance.snapshotTitle, 'Continuation alias bridge');
assert.equal(continuationEnvelope.input.optionCount, 3);
assert.equal(continuationEnvelope.ranked[0].id, 'possible-manual-proof');
assert.equal(continuationEnvelope.ranked[0].provenance.sourceSection, 'ranker-input.possibleNextMoves');
assert.equal(continuationEnvelope.ranked[0].provenance.sourceId, 'possible-move-1');
assert.equal(continuationEnvelope.ranked.find(item => item.id === 'possible-dashboard').lane.id, 'park');
assert.equal(continuationEnvelope.handoff.readiness.status, 'ready');
assert.deepEqual(continuationEnvelope.handoff.warnings, []);
const buildOrderPreviewResponse = await fetch(`${base}/api/rank-feedback`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sourceName: 'Scattermind',
artifactId: 'SM-BUILD-ORDER-PREVIEW-1',
snapshotTitle: 'Build Order Preview alias',
originalPrompt: 'Use a paid Concept Map build order preview without renaming the object.',
context: 'Manual proof first. Avoid saved workspace dashboards.',
conceptMap: {
build_order_preview: {
continue_first: [{ id: 'preview-active-slice', action: 'Preview active slice', evidence_needed: 'Can the preview name one first move?', source_item_id: 'preview-1', source_title: 'Build Order Preview', ranker_hints: { value: 9, effort: 2, confidence: 8, urgency: 8, risk: 2 } }],
evidence_next: [{ id: 'preview-evidence-test', action: 'Preview evidence test', evidence_needed: 'Does the user know what signal to collect?', source_item_id: 'preview-2', source_title: 'Build Order Preview' }],
hold_for_later: [{ id: 'preview-polish', action: 'Preview visual polish', evidence_needed: 'Does polish matter after the proof?', source_item_id: 'preview-3', source_title: 'Build Order Preview' }],
set_aside: [{ id: 'preview-workspace', action: 'Preview workspace dashboard', evidence_needed: 'Not before proof.', source_item_id: 'preview-4', source_title: 'Build Order Preview' }],
},
},
}),
});
assert.equal(buildOrderPreviewResponse.status, 200);
const buildOrderPreview = await buildOrderPreviewResponse.json();
assert.equal(buildOrderPreview.input.optionCount, 4);
assert.equal(buildOrderPreview.ranked[0].id, 'preview-active-slice');
assert.equal(buildOrderPreview.ranked[0].provenance.sourceSection, 'concept-map.buildOrderPreview.doFirst');
assert.equal(buildOrderPreview.ranked.find(item => item.id === 'preview-evidence-test').lane.id, 'test');
assert.equal(buildOrderPreview.ranked.find(item => item.id === 'preview-polish').lane.id, 'defer');
assert.equal(buildOrderPreview.ranked.find(item => item.id === 'preview-workspace').lane.id, 'park');
assert.equal(buildOrderPreview.handoff.readiness.status, 'ready');
assert.deepEqual(buildOrderPreview.handoff.warnings, []);
console.log(JSON.stringify({ ok: true, top: data.ranked[0].id, hintedTop: hinted.ranked[0].id, actionTop: actions.ranked[0].id, nestedConceptTop: nestedConcept.ranked[0].id, nonGoalTop: nonGoal.ranked[0].id, structuredContextTop: structuredContext.ranked[0].id, lensOnlyTop: lensOnly.ranked[0].id, scattermindPaidShapeTop: scattermindPaidShape.ranked[0].id, mergedContextTop: mergedContext.ranked[0].id, embeddedJsonTop: embeddedJson.ranked[0].id, fencedJsonTop: fencedJson.ranked[0].id, embeddedSnapshotTop: embeddedSnapshot.ranked[0].id, sourceExcerptTop: sourceExcerpt.ranked[0].id, snakeCaseBridgeTop: snakeCaseBridge.ranked[0].id, nextStepsAliasTop: nextStepsAlias.ranked[0].id, summaryGuardrailTop: summaryGuardrail.ranked[0].id, bridgeEnvelopeTop: bridgeEnvelope.ranked[0].id, directEnvelopeSectionsTop: directEnvelopeSections.ranked[0].id, softDirectLaneAliasesTop: softDirectLaneAliases.ranked[0].id, threadsFallbackTop: threadsFallback.ranked[0].id, questionsFallbackTop: questionsFallback.ranked[0].id, freeSnapshotTop: freeSnapshot.ranked[0].id, storedScattermindRowTop: storedScattermindRow.ranked[0].id, candidateActionsAliasTop: candidateActionsAlias.ranked[0].id, rankReadyActionsEnvelopeTop: rankReadyActionsEnvelope.ranked[0].id, continuationEnvelopeTop: continuationEnvelope.ranked[0].id, buildOrderPreviewTop: buildOrderPreview.ranked[0].id, duplicateIds: duplicateIds.ranked.map(item => item.id), readiness: data.handoff.readiness.status, provenance: data.input.provenance, buildOrder: data.buildOrder }, null, 2));
} finally { } finally {
server.kill('SIGTERM'); server.kill('SIGTERM');
} }
+32
View File
@@ -495,11 +495,16 @@ function bridgeEnvelopeFrom(input = {}) {
|| body.ranker_input || body.ranker_input
|| body.rankerHandoff || body.rankerHandoff
|| body.ranker_handoff || body.ranker_handoff
|| body.rankerBridge
|| body.ranker_bridge
|| body.rankReady || body.rankReady
|| body.rank_ready || body.rank_ready
|| body.bridge || body.bridge
|| body.bridgePayload || body.bridgePayload
|| body.bridge_payload || body.bridge_payload
|| body.continuation
|| body.continuationPlan
|| body.continuation_plan
); );
} }
@@ -515,6 +520,8 @@ function featureSetFrom(input = {}) {
|| body.candidate_feature_set || body.candidate_feature_set
|| body.rankReadyFeatureSet || body.rankReadyFeatureSet
|| body.rank_ready_feature_set || body.rank_ready_feature_set
|| body.buildOrderPreview
|| body.build_order_preview
|| envelope.featureSet || envelope.featureSet
|| envelope.feature_set || envelope.feature_set
|| envelope.candidateSet || envelope.candidateSet
@@ -523,6 +530,8 @@ function featureSetFrom(input = {}) {
|| envelope.candidate_feature_set || envelope.candidate_feature_set
|| envelope.rankReadyFeatureSet || envelope.rankReadyFeatureSet
|| envelope.rank_ready_feature_set || envelope.rank_ready_feature_set
|| envelope.buildOrderPreview
|| envelope.build_order_preview
); );
} }
@@ -539,11 +548,16 @@ function looksLikeRankPayload(value = {}) {
|| value.ranker_input || value.ranker_input
|| value.rankerHandoff || value.rankerHandoff
|| value.ranker_handoff || value.ranker_handoff
|| value.rankerBridge
|| value.ranker_bridge
|| value.rankReady || value.rankReady
|| value.rank_ready || value.rank_ready
|| value.bridge || value.bridge
|| value.bridgePayload || value.bridgePayload
|| value.bridge_payload || value.bridge_payload
|| value.continuation
|| value.continuationPlan
|| value.continuation_plan
|| value.snapshot || value.snapshot
|| value.conceptMap || value.conceptMap
|| value.concept_map || value.concept_map
@@ -571,6 +585,8 @@ function looksLikeRankPayload(value = {}) {
|| value.full_reading || value.full_reading
|| value.conceptMapJson || value.conceptMapJson
|| value.concept_map_json || value.concept_map_json
|| value.buildOrderPreview
|| value.build_order_preview
|| value.opening_reflection || value.opening_reflection
|| value.restated_idea || value.restated_idea
|| value.ideaText || value.ideaText
@@ -585,6 +601,12 @@ function looksLikeRankPayload(value = {}) {
|| Array.isArray(value.next_actions) || Array.isArray(value.next_actions)
|| Array.isArray(value.nextMoves) || Array.isArray(value.nextMoves)
|| Array.isArray(value.next_moves) || Array.isArray(value.next_moves)
|| Array.isArray(value.possibleNextMoves)
|| Array.isArray(value.possible_next_moves)
|| Array.isArray(value.suggestedNextMoves)
|| Array.isArray(value.suggested_next_moves)
|| Array.isArray(value.recommendations)
|| Array.isArray(value.opportunities)
|| Array.isArray(value.candidates) || Array.isArray(value.candidates)
|| Array.isArray(value.candidateActions) || Array.isArray(value.candidateActions)
|| Array.isArray(value.candidate_actions) || Array.isArray(value.candidate_actions)
@@ -1158,6 +1180,9 @@ function optionsFromBody(body = {}) {
{ items: body.nextMoves || body.next_moves, sourceSection: 'nextMoves' }, { items: body.nextMoves || body.next_moves, sourceSection: 'nextMoves' },
{ items: envelope.nextMoves || envelope.next_moves, sourceSection: 'ranker-input.nextMoves' }, { items: envelope.nextMoves || envelope.next_moves, sourceSection: 'ranker-input.nextMoves' },
{ items: featureSet.nextMoves || featureSet.next_moves, sourceSection: 'feature-set.nextMoves' }, { items: featureSet.nextMoves || featureSet.next_moves, sourceSection: 'feature-set.nextMoves' },
{ items: body.possibleNextMoves || body.possible_next_moves || body.suggestedNextMoves || body.suggested_next_moves || body.recommendations || body.opportunities, sourceSection: 'possibleNextMoves' },
{ items: envelope.possibleNextMoves || envelope.possible_next_moves || envelope.suggestedNextMoves || envelope.suggested_next_moves || envelope.recommendations || envelope.opportunities, sourceSection: 'ranker-input.possibleNextMoves' },
{ items: featureSet.possibleNextMoves || featureSet.possible_next_moves || featureSet.suggestedNextMoves || featureSet.suggested_next_moves || featureSet.recommendations || featureSet.opportunities, sourceSection: 'feature-set.possibleNextMoves' },
{ items: body.candidates, sourceSection: 'candidates' }, { items: body.candidates, sourceSection: 'candidates' },
{ items: envelope.candidates, sourceSection: 'ranker-input.candidates' }, { items: envelope.candidates, sourceSection: 'ranker-input.candidates' },
{ items: featureSet.candidates, sourceSection: 'feature-set.candidates' }, { items: featureSet.candidates, sourceSection: 'feature-set.candidates' },
@@ -1189,6 +1214,7 @@ function optionsFromBody(body = {}) {
const conceptMapCandidateGroup = compactCandidateGroup([ const conceptMapCandidateGroup = compactCandidateGroup([
{ items: conceptMap.nextActions || conceptMap.next_actions || conceptMap.nextSteps || conceptMap.next_steps || conceptMap.recommendedNextSteps || conceptMap.recommended_next_steps || conceptMap.recommendedActions || conceptMap.recommended_actions || conceptMap.suggestedActions || conceptMap.suggested_actions, sourceSection: 'concept-map.nextActions' }, { items: conceptMap.nextActions || conceptMap.next_actions || conceptMap.nextSteps || conceptMap.next_steps || conceptMap.recommendedNextSteps || conceptMap.recommended_next_steps || conceptMap.recommendedActions || conceptMap.recommended_actions || conceptMap.suggestedActions || conceptMap.suggested_actions, sourceSection: 'concept-map.nextActions' },
{ items: conceptMap.nextMoves || conceptMap.next_moves, sourceSection: 'concept-map.nextMoves' }, { items: conceptMap.nextMoves || conceptMap.next_moves, sourceSection: 'concept-map.nextMoves' },
{ items: conceptMap.possibleNextMoves || conceptMap.possible_next_moves || conceptMap.suggestedNextMoves || conceptMap.suggested_next_moves || conceptMap.recommendations || conceptMap.opportunities, sourceSection: 'concept-map.possibleNextMoves' },
{ items: conceptMap.features, sourceSection: 'concept-map.features' }, { items: conceptMap.features, sourceSection: 'concept-map.features' },
{ items: conceptMap.candidates, sourceSection: 'concept-map.candidates' }, { items: conceptMap.candidates, sourceSection: 'concept-map.candidates' },
{ items: conceptMap.candidateActions || conceptMap.candidate_actions || conceptMap.candidateMoves || conceptMap.candidate_moves || conceptMap.rankReadyActions || conceptMap.rank_ready_actions, sourceSection: 'concept-map.candidateActions' }, { items: conceptMap.candidateActions || conceptMap.candidate_actions || conceptMap.candidateMoves || conceptMap.candidate_moves || conceptMap.rankReadyActions || conceptMap.rank_ready_actions, sourceSection: 'concept-map.candidateActions' },
@@ -1203,6 +1229,7 @@ function optionsFromBody(body = {}) {
const snapshotCandidateGroup = compactCandidateGroup([ const snapshotCandidateGroup = compactCandidateGroup([
{ items: snapshot.nextActions || snapshot.next_actions || snapshot.nextSteps || snapshot.next_steps || snapshot.recommendedNextSteps || snapshot.recommended_next_steps || snapshot.recommendedActions || snapshot.recommended_actions || snapshot.suggestedActions || snapshot.suggested_actions, sourceSection: 'snapshot.nextActions' }, { items: snapshot.nextActions || snapshot.next_actions || snapshot.nextSteps || snapshot.next_steps || snapshot.recommendedNextSteps || snapshot.recommended_next_steps || snapshot.recommendedActions || snapshot.recommended_actions || snapshot.suggestedActions || snapshot.suggested_actions, sourceSection: 'snapshot.nextActions' },
{ items: snapshot.nextMoves || snapshot.next_moves, sourceSection: 'snapshot.nextMoves' }, { items: snapshot.nextMoves || snapshot.next_moves, sourceSection: 'snapshot.nextMoves' },
{ items: snapshot.possibleNextMoves || snapshot.possible_next_moves || snapshot.suggestedNextMoves || snapshot.suggested_next_moves || snapshot.recommendations || snapshot.opportunities, sourceSection: 'snapshot.possibleNextMoves' },
{ items: snapshot.actions, sourceSection: 'snapshot.actions' }, { items: snapshot.actions, sourceSection: 'snapshot.actions' },
{ items: snapshot.features, sourceSection: 'snapshot.features' }, { items: snapshot.features, sourceSection: 'snapshot.features' },
{ items: snapshot.candidates, sourceSection: 'snapshot.candidates' }, { items: snapshot.candidates, sourceSection: 'snapshot.candidates' },
@@ -1220,10 +1247,15 @@ function optionsFromBody(body = {}) {
...snapshotCandidateGroup, ...snapshotCandidateGroup,
...conceptMapCandidateGroup, ...conceptMapCandidateGroup,
...buildOrderSectionGroup(body.buildOrder || body.build_order, 'buildOrder'), ...buildOrderSectionGroup(body.buildOrder || body.build_order, 'buildOrder'),
...buildOrderSectionGroup(body.buildOrderPreview || body.build_order_preview, 'buildOrderPreview'),
...buildOrderSectionGroup(envelope.buildOrder || envelope.build_order, 'ranker-input.buildOrder'), ...buildOrderSectionGroup(envelope.buildOrder || envelope.build_order, 'ranker-input.buildOrder'),
...buildOrderSectionGroup(envelope.buildOrderPreview || envelope.build_order_preview, 'ranker-input.buildOrderPreview'),
...buildOrderSectionGroup(featureSet.buildOrder || featureSet.build_order, 'feature-set.buildOrder'), ...buildOrderSectionGroup(featureSet.buildOrder || featureSet.build_order, 'feature-set.buildOrder'),
...buildOrderSectionGroup(featureSet.buildOrderPreview || featureSet.build_order_preview, 'feature-set.buildOrderPreview'),
...buildOrderSectionGroup(snapshot.buildOrder || snapshot.build_order, 'snapshot.buildOrder'), ...buildOrderSectionGroup(snapshot.buildOrder || snapshot.build_order, 'snapshot.buildOrder'),
...buildOrderSectionGroup(snapshot.buildOrderPreview || snapshot.build_order_preview, 'snapshot.buildOrderPreview'),
...buildOrderSectionGroup(conceptMap.buildOrder || conceptMap.build_order, 'concept-map.buildOrder'), ...buildOrderSectionGroup(conceptMap.buildOrder || conceptMap.build_order, 'concept-map.buildOrder'),
...buildOrderSectionGroup(conceptMap.buildOrderPreview || conceptMap.build_order_preview, 'concept-map.buildOrderPreview'),
]; ];
if (groupedCandidates.length) return normalizeCandidateGroup(groupedCandidates); if (groupedCandidates.length) return normalizeCandidateGroup(groupedCandidates);
const buildOrderText = lensContent(conceptMapLenses.channel) const buildOrderText = lensContent(conceptMapLenses.channel)