Accept proof plan bridge aliases

This commit is contained in:
OpenClaw Bot
2026-05-28 00:06:43 +02:00
parent 0b7ca6d009
commit 074892b7e3
5 changed files with 51 additions and 17 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. It also accepts private reading/API envelopes with object-valued `reading` / `fullReading` and `glimpse`, preserving `referenceCode` and `initialPrompt` while treating `reading` as the paid Concept Map. Stringified bridge envelopes in fields such as `rankerInput`, `rankerBridge`, `rankReady`, `bridgePayload`, or `continuationPlan` are expanded the same way, so Appwrite/string-copy handoffs do not have to be manually unwrapped before ranking. 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 into the bridge handoff. 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. It also accepts private reading/API envelopes with object-valued `reading` / `fullReading` and `glimpse`, preserving `referenceCode` and `initialPrompt` while treating `reading` as the paid Concept Map. Stringified bridge envelopes in fields such as `rankerInput`, `rankerBridge`, `rankReady`, `bridgePayload`, or `continuationPlan` are expanded the same way, so Appwrite/string-copy handoffs do not have to be manually unwrapped before ranking. 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 into the bridge handoff.
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`, `Validate manually`, `Manual proof`, `Hold for later`, or `Set aside`, with either colon or reader-friendly dash separators (`Continue first: …`, `Validate manually — …`, `Evidence next - …`). Build Order objects and direct bridge/envelope sections can use matching camel/snake-case keys such as `continueFirst`, `evidenceNext`, `validateManually`, `manualProof`, `holdForLater`, and `setAside`; whole-payload wrappers may use `rankPayload` / `rank_payload` or `scattermindPayload` / `scattermind_payload`, and already-laned objects may be named `rankReadyBuildOrder` / `rank_ready_build_order` as a more explicit Scattermind handoff alias. Those section values may be arrays, a single candidate object, or a reader-friendly string/newline list; Ranker splits scalar sections into candidate actions so Scattermind does not have to wrap every lane in arrays. 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`, laned `buildOrderPreview` / `build_order_preview` objects, first-48-hour action arrays (`next48Hours`, `next_48_hours`, `first48Hours`, `first_48_hours`, `nextTwoDays`, `next_two_days`), evidence-question fallback arrays (`evidenceQuestions` / `evidence_questions`, `proofQuestions` / `proof_questions`, `validationQuestions` / `validation_questions`, `decisionQuestions`, `questionsToAnswer`, `followupQuestions`), and assumption-test arrays (`assumptionTests` / `assumption_tests`, `riskiestAssumptions` / `riskiest_assumptions`, `risksToTest` / `risks_to_test`) that default into Validate next. Direct candidate objects may use reader-friendly prose keys like `text`, `content`, `summary`, `step`, `task`, `instruction`, `why_it_matters`, `evidence_to_collect`, `first_proof_step`, `green_flag`, and `red_flag`; Ranker normalizes those into title, value, evidence, next-step, success, and kill-signal fields so Scattermind does not have to rename paid Concept Map language into software-feature jargon. If a paid Concept Map has no labelled Build Order/action threads but does include `closing_note` / `closingNote` plus decision questions, Ranker treats the closing note as the active 48-hour Do first move and keeps the questions in Validate next. This lets Scattermind pass reader-friendly Concept Map copy without renaming everything into software-feature language. 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`, `Validate manually`, `Manual proof`, `Hold for later`, or `Set aside`, with either colon or reader-friendly dash separators (`Continue first: …`, `Validate manually — …`, `Evidence next - …`). Build Order objects and direct bridge/envelope sections can use matching camel/snake-case keys such as `continueFirst`, `evidenceNext`, `validateManually`, `manualProof`, `holdForLater`, and `setAside`; whole-payload wrappers may use `rankPayload` / `rank_payload` or `scattermindPayload` / `scattermind_payload`, and already-laned objects may be named `rankReadyBuildOrder` / `rank_ready_build_order` as a more explicit Scattermind handoff alias. Those section values may be arrays, a single candidate object, or a reader-friendly string/newline list; Ranker splits scalar sections into candidate actions so Scattermind does not have to wrap every lane in arrays. 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`, laned `buildOrderPreview` / `build_order_preview` objects, first-48-hour action arrays (`next48Hours`, `next_48_hours`, `first48Hours`, `first_48_hours`, `nextTwoDays`, `next_two_days`), evidence-question fallback arrays (`evidenceQuestions` / `evidence_questions`, `proofQuestions` / `proof_questions`, `proofPlan` / `proof_plan`, `validationQuestions` / `validation_questions`, `validationPlan` / `validation_plan`, `decisionQuestions`, `questionsToAnswer`, `followupQuestions`), and assumption-test arrays (`assumptionTests` / `assumption_tests`, `riskiestAssumptions` / `riskiest_assumptions`, `risksToTest` / `risks_to_test`) that default into Validate next. Direct candidate objects may use reader-friendly prose keys like `text`, `content`, `summary`, `step`, `task`, `instruction`, `why_it_matters`, `evidence_to_collect`, `first_proof_step`, `green_flag`, and `red_flag`; Ranker normalizes those into title, value, evidence, next-step, success, and kill-signal fields so Scattermind does not have to rename paid Concept Map language into software-feature jargon. If a paid Concept Map has no labelled Build Order/action threads but does include `closing_note` / `closingNote` plus decision questions, Ranker treats the closing note as the active 48-hour Do first move and keeps the questions in Validate next. This lets Scattermind pass reader-friendly Concept Map copy without renaming everything 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. Ranker now also infers a light `ideaRoute` from the Scattermind source text and carries it in `input.decisionContext` / `handoff.decisionContext`; for game concepts it automatically adds anti-SaaS non-goals so account/dashboard/workspace/subscription candidates cannot win a playable-prototype build order just because they were phrased loudly. 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. Ranker now also infers a light `ideaRoute` from the Scattermind source text and carries it in `input.decisionContext` / `handoff.decisionContext`; for game concepts it automatically adds anti-SaaS non-goals so account/dashboard/workspace/subscription candidates cannot win a playable-prototype build order just because they were phrased loudly. 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.
+1 -1
View File
@@ -81,7 +81,7 @@ function parsePastedJsonPayload(value) {
|| 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)
|| Array.isArray(parsed.parkingLot) || Array.isArray(parsed.parking_lot) || Array.isArray(parsed.setAside) || Array.isArray(parsed.set_aside) || Array.isArray(parsed.parkingLot) || Array.isArray(parsed.parking_lot) || Array.isArray(parsed.setAside) || Array.isArray(parsed.set_aside)
|| Array.isArray(parsed.threads_to_hold) || Array.isArray(parsed.threadsToHold) || Array.isArray(parsed.actionThreads) || Array.isArray(parsed.action_threads) || Array.isArray(parsed.threads_to_hold) || Array.isArray(parsed.threadsToHold) || Array.isArray(parsed.actionThreads) || Array.isArray(parsed.action_threads)
|| Array.isArray(parsed.questions_to_sit_with) || Array.isArray(parsed.questionsToSitWith) || Array.isArray(parsed.evidenceQuestions) || Array.isArray(parsed.evidence_questions) || Array.isArray(parsed.proofQuestions) || Array.isArray(parsed.proof_questions) || Array.isArray(parsed.validationQuestions) || Array.isArray(parsed.validation_questions) || Array.isArray(parsed.decisionQuestions) || Array.isArray(parsed.decision_questions) || Array.isArray(parsed.questionsToAnswer) || Array.isArray(parsed.questions_to_answer) || Array.isArray(parsed.followupQuestions) || Array.isArray(parsed.followup_questions) || Array.isArray(parsed.openQuestions) || Array.isArray(parsed.open_questions) || Array.isArray(parsed.questions_to_sit_with) || Array.isArray(parsed.questionsToSitWith) || Array.isArray(parsed.evidenceQuestions) || Array.isArray(parsed.evidence_questions) || Array.isArray(parsed.proofQuestions) || Array.isArray(parsed.proof_questions) || Array.isArray(parsed.proofPlan) || Array.isArray(parsed.proof_plan) || Array.isArray(parsed.validationQuestions) || Array.isArray(parsed.validation_questions) || Array.isArray(parsed.validationPlan) || Array.isArray(parsed.validation_plan) || Array.isArray(parsed.decisionQuestions) || Array.isArray(parsed.decision_questions) || Array.isArray(parsed.questionsToAnswer) || Array.isArray(parsed.questions_to_answer) || Array.isArray(parsed.followupQuestions) || Array.isArray(parsed.followup_questions) || Array.isArray(parsed.openQuestions) || Array.isArray(parsed.open_questions)
|| Array.isArray(parsed.assumptionTests) || Array.isArray(parsed.assumption_tests) || Array.isArray(parsed.riskiestAssumptions) || Array.isArray(parsed.riskiest_assumptions) || Array.isArray(parsed.risksToTest) || Array.isArray(parsed.risks_to_test) || Array.isArray(parsed.assumptionTests) || Array.isArray(parsed.assumption_tests) || Array.isArray(parsed.riskiestAssumptions) || Array.isArray(parsed.riskiest_assumptions) || Array.isArray(parsed.risksToTest) || Array.isArray(parsed.risks_to_test)
); );
return looksLikeBridgePayload ? parsed : null; return looksLikeBridgePayload ? parsed : null;
+3 -3
View File
@@ -4,9 +4,9 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#f3eee4" /> <meta name="theme-color" content="#f3eee4" />
<meta name="rank-version" content="2.2.1-source-trace-paste" /> <meta name="rank-version" content="2.2.2-proof-plan-alias" />
<title>Ranker — feedback front door for messy decisions</title> <title>Ranker — feedback front door for messy decisions</title>
<link rel="stylesheet" href="/styles.css?v=2.2.1-source-trace-paste" /> <link rel="stylesheet" href="/styles.css?v=2.2.2-proof-plan-alias" />
</head> </head>
<body> <body>
<main class="page-shell"> <main class="page-shell">
@@ -127,6 +127,6 @@ Or paste a Scattermind Concept Map JSON object here; Ranker will preserve source
</main> </main>
<div class="toast" id="toast" hidden></div> <div class="toast" id="toast" hidden></div>
<script src="/app.js?v=2.2.1-source-trace-paste" type="module"></script> <script src="/app.js?v=2.2.2-proof-plan-alias" type="module"></script>
</body> </body>
</html> </html>
+31 -1
View File
@@ -2520,7 +2520,37 @@ try {
assert.equal(rankedBuildOrderAlias.handoff.readiness.status, 'ready'); assert.equal(rankedBuildOrderAlias.handoff.readiness.status, 'ready');
assert.deepEqual(rankedBuildOrderAlias.handoff.warnings, []); assert.deepEqual(rankedBuildOrderAlias.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, scattermindRoadmapLanguageTop: scattermindRoadmapLanguage.ranked[0].id, scattermindRoadmapLensOnlyTop: scattermindRoadmapLensOnly.ranked[0].id, stringifiedRankerInputTop: stringifiedRankerInput.ranked[0].id, scalarBuildOrderSectionsTop: scalarBuildOrderSections.ranked[0].id, snakeReaderFriendlyBuildOrderTop: snakeReaderFriendlyBuildOrder.ranked[0].id, readerFriendlyLensLabelTop: readerFriendlyLensLabel.ranked[0].id, gameRouteGuardrailTop: gameRouteGuardrail.ranked[0].id, rankedBuildOrderAliasTop: rankedBuildOrderAlias.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 proofPlanAliasResponse = await fetch(`${base}/api/rank-feedback`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sourceName: 'Scattermind',
referenceCode: 'SM-PROOF-PLAN-ALIAS-1',
working_name: 'Proof Plan alias export',
ideaText: 'Scattermind exported a reader-facing proof plan and validation plan instead of software feature names.',
context: 'Solo builder. Manual proof first. Avoid account dashboards and saved workspaces until proof.',
mode: 'validation',
conceptMap: {
doFirst: [{ id: 'proof-plan-active', action: 'One-call source-traced proof offer', evidence_needed: 'Can one target user explain the first move after reading the receipt?', source_item_id: 'proof-plan-active-1', source_title: 'Build Order', ranker_hints: { value: 8, effort: 2, confidence: 7, urgency: 8, risk: 2 } }],
proof_plan: [{ id: 'proof-plan-call', action: 'Run the first proof call', evidence_needed: 'Does a tired user understand the active slice without a dashboard?', source_item_id: 'proof-plan-1', source_title: 'Proof Plan' }],
validation_plan: [{ id: 'validation-plan-recheck', action: 'Re-rank after the proof call', evidence_needed: 'Did the first proof change the defended build order?', source_item_id: 'validation-plan-1', source_title: 'Validation Plan' }],
parkingLot: [{ id: 'proof-plan-dashboard', action: 'Saved proof dashboard with accounts and billing', evidence_needed: 'Not before proof.', source_item_id: 'parking-1', source_title: 'Parking Lot' }],
},
}),
});
assert.equal(proofPlanAliasResponse.status, 200);
const proofPlanAlias = await proofPlanAliasResponse.json();
assert.equal(proofPlanAlias.input.optionCount, 4, 'proof_plan / validation_plan should become validate-next candidates without renaming them to features');
assert.equal(proofPlanAlias.ranked[0].id, 'proof-plan-active');
assert.equal(proofPlanAlias.ranked.find(item => item.id === 'proof-plan-call').lane.id, 'test');
assert.equal(proofPlanAlias.ranked.find(item => item.id === 'validation-plan-recheck').lane.id, 'test');
assert.equal(proofPlanAlias.ranked.find(item => item.id === 'proof-plan-dashboard').lane.id, 'park');
assert.equal(proofPlanAlias.ranked.find(item => item.id === 'proof-plan-call').provenance.sourceSection, 'concept-map.experiments');
assert.equal(proofPlanAlias.handoff.readiness.status, 'ready');
assert.deepEqual(proofPlanAlias.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, scattermindRoadmapLanguageTop: scattermindRoadmapLanguage.ranked[0].id, scattermindRoadmapLensOnlyTop: scattermindRoadmapLensOnly.ranked[0].id, stringifiedRankerInputTop: stringifiedRankerInput.ranked[0].id, scalarBuildOrderSectionsTop: scalarBuildOrderSections.ranked[0].id, snakeReaderFriendlyBuildOrderTop: snakeReaderFriendlyBuildOrder.ranked[0].id, readerFriendlyLensLabelTop: readerFriendlyLensLabel.ranked[0].id, gameRouteGuardrailTop: gameRouteGuardrail.ranked[0].id, rankedBuildOrderAliasTop: rankedBuildOrderAlias.ranked[0].id, proofPlanAliasTop: proofPlanAlias.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');
} }
+15 -11
View File
@@ -668,8 +668,12 @@ function looksLikeRankPayload(value = {}) {
|| Array.isArray(value.evidence_questions) || Array.isArray(value.evidence_questions)
|| Array.isArray(value.proofQuestions) || Array.isArray(value.proofQuestions)
|| Array.isArray(value.proof_questions) || Array.isArray(value.proof_questions)
|| Array.isArray(value.proofPlan)
|| Array.isArray(value.proof_plan)
|| Array.isArray(value.validationQuestions) || Array.isArray(value.validationQuestions)
|| Array.isArray(value.validation_questions) || Array.isArray(value.validation_questions)
|| Array.isArray(value.validationPlan)
|| Array.isArray(value.validation_plan)
|| Array.isArray(value.decisionQuestions) || Array.isArray(value.decisionQuestions)
|| Array.isArray(value.decision_questions) || Array.isArray(value.decision_questions)
|| Array.isArray(value.questionsToAnswer) || Array.isArray(value.questionsToAnswer)
@@ -1195,7 +1199,7 @@ function buildOrderSectionGroup(buildOrder = {}, baseSection = 'buildOrder') {
const source = objectFrom(buildOrder); const source = objectFrom(buildOrder);
return compactCandidateGroup([ return compactCandidateGroup([
{ items: source.doFirst || source.do_first || source.buildFirst || source.build_first || source.buildNow || source.build_now || source.now || source.continueFirst || source.continue_first || source.makeTangible || source.make_tangible || source.startHere || source.start_here || source.startNow || source.start_now || source.shipFirst || source.ship_first, sourceSection: `${baseSection}.doFirst`, defaultLane: 'do-first' }, { items: source.doFirst || source.do_first || source.buildFirst || source.build_first || source.buildNow || source.build_now || source.now || source.continueFirst || source.continue_first || source.makeTangible || source.make_tangible || source.startHere || source.start_here || source.startNow || source.start_now || source.shipFirst || source.ship_first, sourceSection: `${baseSection}.doFirst`, defaultLane: 'do-first' },
{ items: source.validateNext || source.validate_next || source.validateManually || source.validate_manually || source.testNext || source.test_next || source.testManually || source.test_manually || source.manualProof || source.manual_proof || source.validation || source.evidenceNext || source.evidence_next || source.tryNext || source.try_next || source.learnNext || source.learn_next || source.proofStep || source.proof_step || source.proofSteps || source.proof_steps, sourceSection: `${baseSection}.validateNext`, defaultLane: 'validate-next' }, { items: source.validateNext || source.validate_next || source.validateManually || source.validate_manually || source.testNext || source.test_next || source.testManually || source.test_manually || source.manualProof || source.manual_proof || source.validation || source.validationPlan || source.validation_plan || source.evidenceNext || source.evidence_next || source.tryNext || source.try_next || source.learnNext || source.learn_next || source.proofStep || source.proof_step || source.proofSteps || source.proof_steps || source.proofPlan || source.proof_plan, sourceSection: `${baseSection}.validateNext`, defaultLane: 'validate-next' },
{ items: source.defer || source.deferred || source.later || source.afterProof || source.after_proof || source.holdForLater || source.hold_for_later || source.notYet || source.not_yet || source.leaveOut || source.leave_out || source.skipForNow || source.skip_for_now || source.doNotBuildYet || source.do_not_build_yet, sourceSection: `${baseSection}.defer`, defaultLane: 'defer' }, { items: source.defer || source.deferred || source.later || source.afterProof || source.after_proof || source.holdForLater || source.hold_for_later || source.notYet || source.not_yet || source.leaveOut || source.leave_out || source.skipForNow || source.skip_for_now || source.doNotBuildYet || source.do_not_build_yet, sourceSection: `${baseSection}.defer`, defaultLane: 'defer' },
{ items: source.park || source.parkingLot || source.parking_lot || source.parked || source.probablyNoise || source.probably_noise || source.noise || source.setAside || source.set_aside || source.outOfScope || source.out_of_scope || source.cut || source.distractions, sourceSection: `${baseSection}.park`, defaultLane: 'park' }, { items: source.park || source.parkingLot || source.parking_lot || source.parked || source.probablyNoise || source.probably_noise || source.noise || source.setAside || source.set_aside || source.outOfScope || source.out_of_scope || source.cut || source.distractions, sourceSection: `${baseSection}.park`, defaultLane: 'park' },
]); ]);
@@ -1495,16 +1499,16 @@ function optionsFromBody(body = {}) {
{ items: envelope.doFirst || envelope.do_first || envelope.buildFirst || envelope.build_first || envelope.buildNow || envelope.build_now || envelope.continueFirst || envelope.continue_first || envelope.makeTangible || envelope.make_tangible || envelope.startHere || envelope.start_here, sourceSection: 'ranker-input.doFirst', defaultLane: 'do-first' }, { items: envelope.doFirst || envelope.do_first || envelope.buildFirst || envelope.build_first || envelope.buildNow || envelope.build_now || envelope.continueFirst || envelope.continue_first || envelope.makeTangible || envelope.make_tangible || envelope.startHere || envelope.start_here, sourceSection: 'ranker-input.doFirst', defaultLane: 'do-first' },
{ items: featureSet.doFirst || featureSet.do_first || featureSet.buildFirst || featureSet.build_first || featureSet.buildNow || featureSet.build_now || featureSet.continueFirst || featureSet.continue_first || featureSet.makeTangible || featureSet.make_tangible || featureSet.startHere || featureSet.start_here, sourceSection: 'feature-set.doFirst', defaultLane: 'do-first' }, { items: featureSet.doFirst || featureSet.do_first || featureSet.buildFirst || featureSet.build_first || featureSet.buildNow || featureSet.build_now || featureSet.continueFirst || featureSet.continue_first || featureSet.makeTangible || featureSet.make_tangible || featureSet.startHere || featureSet.start_here, sourceSection: 'feature-set.doFirst', defaultLane: 'do-first' },
{ items: body.experiments, sourceSection: 'experiments', defaultLane: 'validate-next' }, { items: body.experiments, sourceSection: 'experiments', defaultLane: 'validate-next' },
{ items: body.validationTests || body.validation_tests, sourceSection: 'experiments', defaultLane: 'validate-next' }, { items: body.validationTests || body.validation_tests || body.validationPlan || body.validation_plan, sourceSection: 'experiments', defaultLane: 'validate-next' },
{ items: body.proofTests || body.proof_tests, 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.assumptionTests || body.assumption_tests || body.riskiestAssumptions || body.riskiest_assumptions || body.risksToTest || body.risks_to_test, sourceSection: 'assumptionTests', defaultLane: 'validate-next' },
{ items: envelope.experiments, sourceSection: 'ranker-input.experiments', defaultLane: 'validate-next' }, { items: envelope.experiments, sourceSection: 'ranker-input.experiments', defaultLane: 'validate-next' },
{ items: envelope.validationTests || envelope.validation_tests, 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, 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.assumptionTests || envelope.assumption_tests || envelope.riskiestAssumptions || envelope.riskiest_assumptions || envelope.risksToTest || envelope.risks_to_test, sourceSection: 'ranker-input.assumptionTests', defaultLane: 'validate-next' },
{ items: featureSet.experiments, sourceSection: 'feature-set.experiments', defaultLane: 'validate-next' }, { items: featureSet.experiments, sourceSection: 'feature-set.experiments', defaultLane: 'validate-next' },
{ items: featureSet.validationTests || featureSet.validation_tests, 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, 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.assumptionTests || featureSet.assumption_tests || featureSet.riskiestAssumptions || featureSet.riskiest_assumptions || featureSet.risksToTest || featureSet.risks_to_test, sourceSection: 'feature-set.assumptionTests', defaultLane: 'validate-next' },
{ 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.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.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' },
@@ -1527,8 +1531,8 @@ function optionsFromBody(body = {}) {
{ items: conceptMap.doFirst || conceptMap.do_first || conceptMap.buildFirst || conceptMap.build_first || conceptMap.buildNow || conceptMap.build_now || conceptMap.continueFirst || conceptMap.continue_first || conceptMap.makeTangible || conceptMap.make_tangible || conceptMap.startHere || conceptMap.start_here, sourceSection: 'concept-map.doFirst', defaultLane: 'do-first' }, { items: conceptMap.doFirst || conceptMap.do_first || conceptMap.buildFirst || conceptMap.build_first || conceptMap.buildNow || conceptMap.build_now || conceptMap.continueFirst || conceptMap.continue_first || conceptMap.makeTangible || conceptMap.make_tangible || conceptMap.startHere || conceptMap.start_here, sourceSection: 'concept-map.doFirst', defaultLane: 'do-first' },
{ items: conceptMap.validateNext || conceptMap.validate_next || conceptMap.validateManually || conceptMap.validate_manually || conceptMap.validate || conceptMap.validation || conceptMap.evidenceNext || conceptMap.evidence_next || conceptMap.tryNext || conceptMap.try_next || conceptMap.learnNext || conceptMap.learn_next || conceptMap.testManually || conceptMap.test_manually || conceptMap.manualProof || conceptMap.manual_proof, sourceSection: 'concept-map.validateNext', defaultLane: 'validate-next' }, { items: conceptMap.validateNext || conceptMap.validate_next || conceptMap.validateManually || conceptMap.validate_manually || conceptMap.validate || conceptMap.validation || conceptMap.evidenceNext || conceptMap.evidence_next || conceptMap.tryNext || conceptMap.try_next || conceptMap.learnNext || conceptMap.learn_next || conceptMap.testManually || conceptMap.test_manually || conceptMap.manualProof || conceptMap.manual_proof, sourceSection: 'concept-map.validateNext', defaultLane: 'validate-next' },
{ items: conceptMap.experiments, sourceSection: 'concept-map.experiments', defaultLane: 'validate-next' }, { items: conceptMap.experiments, sourceSection: 'concept-map.experiments', defaultLane: 'validate-next' },
{ items: conceptMap.validationTests || conceptMap.validation_tests, sourceSection: 'concept-map.experiments', defaultLane: 'validate-next' }, { items: conceptMap.validationTests || conceptMap.validation_tests || conceptMap.validationPlan || conceptMap.validation_plan, sourceSection: 'concept-map.experiments', defaultLane: 'validate-next' },
{ items: conceptMap.proofTests || conceptMap.proof_tests, 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.assumptionTests || conceptMap.assumption_tests || conceptMap.riskiestAssumptions || conceptMap.riskiest_assumptions || conceptMap.risksToTest || conceptMap.risks_to_test, sourceSection: 'concept-map.assumptionTests', defaultLane: 'validate-next' },
{ 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.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' }, { 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' },
@@ -1545,8 +1549,8 @@ function optionsFromBody(body = {}) {
{ items: snapshot.doFirst || snapshot.do_first || snapshot.buildFirst || snapshot.build_first || snapshot.buildNow || snapshot.build_now || snapshot.continueFirst || snapshot.continue_first || snapshot.makeTangible || snapshot.make_tangible || snapshot.startHere || snapshot.start_here, sourceSection: 'snapshot.doFirst', defaultLane: 'do-first' }, { items: snapshot.doFirst || snapshot.do_first || snapshot.buildFirst || snapshot.build_first || snapshot.buildNow || snapshot.build_now || snapshot.continueFirst || snapshot.continue_first || snapshot.makeTangible || snapshot.make_tangible || snapshot.startHere || snapshot.start_here, sourceSection: 'snapshot.doFirst', defaultLane: 'do-first' },
{ items: snapshot.validateNext || snapshot.validate_next || snapshot.validateManually || snapshot.validate_manually || snapshot.validate || snapshot.validation || snapshot.evidenceNext || snapshot.evidence_next || snapshot.tryNext || snapshot.try_next || snapshot.learnNext || snapshot.learn_next || snapshot.testManually || snapshot.test_manually || snapshot.manualProof || snapshot.manual_proof, sourceSection: 'snapshot.validateNext', defaultLane: 'validate-next' }, { items: snapshot.validateNext || snapshot.validate_next || snapshot.validateManually || snapshot.validate_manually || snapshot.validate || snapshot.validation || snapshot.evidenceNext || snapshot.evidence_next || snapshot.tryNext || snapshot.try_next || snapshot.learnNext || snapshot.learn_next || snapshot.testManually || snapshot.test_manually || snapshot.manualProof || snapshot.manual_proof, sourceSection: 'snapshot.validateNext', defaultLane: 'validate-next' },
{ items: snapshot.experiments, sourceSection: 'snapshot.experiments', defaultLane: 'validate-next' }, { items: snapshot.experiments, sourceSection: 'snapshot.experiments', defaultLane: 'validate-next' },
{ items: snapshot.validationTests || snapshot.validation_tests, sourceSection: 'snapshot.experiments', defaultLane: 'validate-next' }, { items: snapshot.validationTests || snapshot.validation_tests || snapshot.validationPlan || snapshot.validation_plan, sourceSection: 'snapshot.experiments', defaultLane: 'validate-next' },
{ items: snapshot.proofTests || snapshot.proof_tests, 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.assumptionTests || snapshot.assumption_tests || snapshot.riskiestAssumptions || snapshot.riskiest_assumptions || snapshot.risksToTest || snapshot.risks_to_test, sourceSection: 'snapshot.assumptionTests', defaultLane: 'validate-next' },
{ 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.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' }, { 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' },