Accept nested proof gate bridge fields
This commit is contained in:
@@ -47,7 +47,7 @@ Ranker's continuation job is narrow:
|
|||||||
|
|
||||||
`POST /api/rank-feedback` accepts a `prioritix-feature-set-v1`-style payload from Scattermind and returns ranked items plus `buildOrder.doFirst / validateNext / defer / park`. It accepts candidate arrays as `features`, `actions`, `nextMoves`, `candidates`, `experiments`, `validationTests`, or `proofTests` either at the top level or under `featureSet`, and it can consume nested Snapshot or Concept Map artifacts directly, so Scattermind can hand off `snapshot.nextActions / nextMoves / recommendedActions / suggestedActions` or `conceptMap.nextActions / nextMoves / recommendedActions / suggestedActions` without renaming them into fake software features. Experiment/proof-test arrays default into Validate next candidates, preserving source provenance while keeping them out of the active build-first lane. Sectioned Concept Maps may also include `validateNext`, `deferred`, and `parkingLot`; Ranker combines those sections into one build-order pass while preserving `sourceSection` and treating deferred/parked sections as lane hints. Ranker also accepts an already-laned Build Order object at top level, under `featureSet`, or as `conceptMap.buildOrder` / `conceptMap.buildOrderPreview` / `conceptMap.rankedBuildOrder` (`doFirst` / `validateNext` / `deferred` / `parkingLot`, with aliases like `buildNow`, `testManually`, and `probablyNoise`). String items in those lanes are normalized into candidate actions, while object items can use `move`, `questionToAnswer`, or `evidenceQuestion` aliases. Normalized candidate objects may also use `lane` as a lane hint (`do-first`, `validate-next`, `defer`, `park`) without overwriting `sourceSection`, so Scattermind exports that separate recommendation from provenance remain traceable. Empty wrapper arrays are ignored rather than allowed to shadow a real nested Concept Map action set, and non-empty normalized wrappers are merged with Concept Map validation/deferred/parking sections rather than dropping that context. That keeps partially-normalized Scattermind exports rankable without losing the source lane contract. It also returns a `brief` with source, next-48-hour actions, carried-forward assumptions, source trace, and what would change the ranking, plus `handoff.copyableText`: a plain-text Build Order handoff with Do first / Validate next / Defer / Park, readiness, carried context, source trace, and the explicit rule that only the Do first item is active. This gives Scattermind (or a tired copy/paste user) a stable artifact to save without reconstructing the decision from JSON fields. Lane-level `buildOrderDetails` still carry each item's reason, next step, evidence question, success/kill signals, source section, lane source, score, and confidence, while the `handoff` object (`rank-feedback-result-v1`) carries source provenance, item trace rows, explicit next-step/success/kill signals when Scattermind provides them, copyable text, and contract warnings for missing artifact IDs, source sections, original prompt provenance, or evidence on active items. If Scattermind sends the current paid Concept Map shape as lenses rather than arrays, Ranker can parse `conceptMap.lenses.channel.content` / `buildOrder` labels (`Build first`, `Test manually`, `Defer`, `Probably noise`) into rank-ready candidates and can read guardrails from the risk lens. Keep this contract action-first; do not use it as a reason to add generic dashboard, auth, billing, or workspace layers before the bridge has proof.
|
`POST /api/rank-feedback` accepts a `prioritix-feature-set-v1`-style payload from Scattermind and returns ranked items plus `buildOrder.doFirst / validateNext / defer / park`. It accepts candidate arrays as `features`, `actions`, `nextMoves`, `candidates`, `experiments`, `validationTests`, or `proofTests` either at the top level or under `featureSet`, and it can consume nested Snapshot or Concept Map artifacts directly, so Scattermind can hand off `snapshot.nextActions / nextMoves / recommendedActions / suggestedActions` or `conceptMap.nextActions / nextMoves / recommendedActions / suggestedActions` without renaming them into fake software features. Experiment/proof-test arrays default into Validate next candidates, preserving source provenance while keeping them out of the active build-first lane. Sectioned Concept Maps may also include `validateNext`, `deferred`, and `parkingLot`; Ranker combines those sections into one build-order pass while preserving `sourceSection` and treating deferred/parked sections as lane hints. Ranker also accepts an already-laned Build Order object at top level, under `featureSet`, or as `conceptMap.buildOrder` / `conceptMap.buildOrderPreview` / `conceptMap.rankedBuildOrder` (`doFirst` / `validateNext` / `deferred` / `parkingLot`, with aliases like `buildNow`, `testManually`, and `probablyNoise`). String items in those lanes are normalized into candidate actions, while object items can use `move`, `questionToAnswer`, or `evidenceQuestion` aliases. Normalized candidate objects may also use `lane` as a lane hint (`do-first`, `validate-next`, `defer`, `park`) without overwriting `sourceSection`, so Scattermind exports that separate recommendation from provenance remain traceable. Empty wrapper arrays are ignored rather than allowed to shadow a real nested Concept Map action set, and non-empty normalized wrappers are merged with Concept Map validation/deferred/parking sections rather than dropping that context. That keeps partially-normalized Scattermind exports rankable without losing the source lane contract. It also returns a `brief` with source, next-48-hour actions, carried-forward assumptions, source trace, and what would change the ranking, plus `handoff.copyableText`: a plain-text Build Order handoff with Do first / Validate next / Defer / Park, readiness, carried context, source trace, and the explicit rule that only the Do first item is active. This gives Scattermind (or a tired copy/paste user) a stable artifact to save without reconstructing the decision from JSON fields. Lane-level `buildOrderDetails` still carry each item's reason, next step, evidence question, success/kill signals, source section, lane source, score, and confidence, while the `handoff` object (`rank-feedback-result-v1`) carries source provenance, item trace rows, explicit next-step/success/kill signals when Scattermind provides them, copyable text, and contract warnings for missing artifact IDs, source sections, original prompt provenance, or evidence on active items. If Scattermind sends the current paid Concept Map shape as lenses rather than arrays, Ranker can parse `conceptMap.lenses.channel.content` / `buildOrder` labels (`Build first`, `Test manually`, `Defer`, `Probably noise`) into rank-ready candidates and can read guardrails from the risk lens. Keep this contract action-first; do not use it as a reason to add generic dashboard, auth, billing, or workspace layers before the bridge has proof.
|
||||||
|
|
||||||
Candidate items may include optional 1–10 `rankerHints` (`value`, `effort`, `confidence`, `urgency`, `revenue`, `novelty`, `risk`). Ranker blends those explicit Scattermind hints with text heuristics; `effort` is inverted into feasibility. Hints improve the defended order, but `recommendedLane: "defer"` or `"park"` remains a safety rail so dashboard-swamp items do not get promoted by flashy wording. For clean bridge handoff, Scattermind should send `sourceSection` and `evidenceNeeded` on each active next move. Scattermind can also send `targetAudience`, `constraints`, `assumptions`, and `nonGoals` / `avoid` at the top level, in `featureSet`, inside `snapshot.context` or `conceptMap.context`, or as a structured top-level `context` object with `summary`, `targetAudience`, `constraints`, `nonGoals` / `avoid`, and `assumptions`; Ranker merges these sources rather than letting a shallow wrapper context shadow deeper artifact guardrails. Ranker also accepts structured `decisionContext` / `decision_context`, `rankerContext` / `ranker_context`, `handoffContext` / `handoff_context`, and `bridgeContext` / `bridge_context` objects at the top level, inside bridge envelopes, feature sets, artifacts, Snapshots, or Concept Maps, so Scattermind can keep context in a machine-named contract field without losing guardrails. Lens-only Concept Maps may additionally send audience / constraints / assumptions / risk lens content, and Ranker will split sentence-style lens notes into readable decision context instead of leaking `[object Object]`. If Scattermind only has a flat context string or schema-light structured context summaries (`context.summary`, `snapshot.context.summary`, `conceptMap.context.summary`, etc.), Ranker extracts simple guardrails such as `Solo builder`, `Manual proof`, `Avoid ...`, `No ...`, `Non-goal: ...`, `Not yet ...`, and `Do not ...` into `input.decisionContext` / `handoff.decisionContext` so early bridge exports still protect against dashboard/auth/billing drift. Ranker returns that decision context in `input.decisionContext` and `handoff.decisionContext`, and penalizes candidates that conflict with source non-goals (for example saved workspaces/auth/billing before the continuation proof). If Scattermind sends duplicate candidate IDs, Ranker keeps the first ID, suffixes later duplicates (`preview-2`), and reports the normalization in `handoff.warnings` / `handoff.itemTrace` so downstream build-order references remain addressable. Ranker also accepts Scattermind's paid Concept Map object directly when it arrives with top-level `reference_code`, `working_name`, `ideaText`, and string-valued `lenses.channel` / `lenses.risk` fields; the reference code becomes source provenance, the working name becomes the source title, and labelled Build Order text is turned into rank-ready candidates without requiring Scattermind to wrap it first.
|
Candidate items may include optional 1–10 `rankerHints` (`value`, `effort`, `confidence`, `urgency`, `revenue`, `novelty`, `risk`) and nested `proofGate` / `proof_gate` / `validationGate` objects with `nextStep`, `evidenceQuestion`, `successCriteria` / `passSignal`, `stopSignal` / `killSignal`, and proof `steps`; Ranker flattens that proof gate into the active slice, first-screen receipt, and handoff contract so Scattermind does not have to duplicate every proof field at candidate top level. Ranker blends those explicit Scattermind hints with text heuristics; `effort` is inverted into feasibility. Hints improve the defended order, but `recommendedLane: "defer"` or `"park"` remains a safety rail so dashboard-swamp items do not get promoted by flashy wording. For clean bridge handoff, Scattermind should send `sourceSection` and `evidenceNeeded` on each active next move. Scattermind can also send `targetAudience`, `constraints`, `assumptions`, and `nonGoals` / `avoid` at the top level, in `featureSet`, inside `snapshot.context` or `conceptMap.context`, or as a structured top-level `context` object with `summary`, `targetAudience`, `constraints`, `nonGoals` / `avoid`, and `assumptions`; Ranker merges these sources rather than letting a shallow wrapper context shadow deeper artifact guardrails. Ranker also accepts structured `decisionContext` / `decision_context`, `rankerContext` / `ranker_context`, `handoffContext` / `handoff_context`, and `bridgeContext` / `bridge_context` objects at the top level, inside bridge envelopes, feature sets, artifacts, Snapshots, or Concept Maps, so Scattermind can keep context in a machine-named contract field without losing guardrails. Lens-only Concept Maps may additionally send audience / constraints / assumptions / risk lens content, and Ranker will split sentence-style lens notes into readable decision context instead of leaking `[object Object]`. If Scattermind only has a flat context string or schema-light structured context summaries (`context.summary`, `snapshot.context.summary`, `conceptMap.context.summary`, etc.), Ranker extracts simple guardrails such as `Solo builder`, `Manual proof`, `Avoid ...`, `No ...`, `Non-goal: ...`, `Not yet ...`, and `Do not ...` into `input.decisionContext` / `handoff.decisionContext` so early bridge exports still protect against dashboard/auth/billing drift. Ranker returns that decision context in `input.decisionContext` and `handoff.decisionContext`, and penalizes candidates that conflict with source non-goals (for example saved workspaces/auth/billing before the continuation proof). If Scattermind sends duplicate candidate IDs, Ranker keeps the first ID, suffixes later duplicates (`preview-2`), and reports the normalization in `handoff.warnings` / `handoff.itemTrace` so downstream build-order references remain addressable. Ranker also accepts Scattermind's paid Concept Map object directly when it arrives with top-level `reference_code`, `working_name`, `ideaText`, and string-valued `lenses.channel` / `lenses.risk` fields; the reference code becomes source provenance, the working name becomes the source title, and labelled Build Order text is turned into rank-ready candidates without requiring Scattermind to wrap it first.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
|||||||
@@ -2581,6 +2581,55 @@ try {
|
|||||||
assert.equal(proofPlanAlias.handoff.readiness.status, 'ready');
|
assert.equal(proofPlanAlias.handoff.readiness.status, 'ready');
|
||||||
assert.deepEqual(proofPlanAlias.handoff.warnings, []);
|
assert.deepEqual(proofPlanAlias.handoff.warnings, []);
|
||||||
|
|
||||||
|
const proofGateAliasResponse = await fetch(`${base}/api/rank-feedback`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
sourceName: 'Scattermind',
|
||||||
|
referenceCode: 'SM-PROOF-GATE-1',
|
||||||
|
working_name: 'Nested proof gate export',
|
||||||
|
ideaText: 'Scattermind exported the build order with nested proof_gate objects instead of flattening every proof field onto the candidate.',
|
||||||
|
context: 'Solo builder. Manual proof first. Avoid account dashboards and saved workspaces until proof.',
|
||||||
|
mode: 'validation',
|
||||||
|
conceptMap: {
|
||||||
|
nextActions: [
|
||||||
|
{
|
||||||
|
id: 'nested-proof-gate-active',
|
||||||
|
title: 'Nested proof-gated active slice',
|
||||||
|
description: 'Show the active source-traced move with one proof gate.',
|
||||||
|
source_item_id: 'proof-gate-1',
|
||||||
|
source_title: 'Nested proof gate',
|
||||||
|
proof_gate: {
|
||||||
|
next_step: 'Run the source-traced proof script with one non-AI-native user.',
|
||||||
|
evidence_question: 'Can the user explain the active move without seeing a dashboard?',
|
||||||
|
success_criteria: 'The user names the first move and the thing not to build yet.',
|
||||||
|
stop_signal: 'The user asks for a workspace, account, or setup before understanding the first move.',
|
||||||
|
steps: ['Read the active slice aloud', 'Ask what they would do next'],
|
||||||
|
},
|
||||||
|
ranker_hints: { value: 9, effort: 2, confidence: 8, urgency: 8, risk: 2 },
|
||||||
|
},
|
||||||
|
{ id: 'nested-proof-gate-copy', title: 'Copy the proof-gated receipt', evidence_needed: 'Does the copied receipt preserve the source trace?', recommendedLane: 'validate-next', source_item_id: 'proof-gate-2', source_title: 'Nested proof gate' },
|
||||||
|
{ id: 'nested-proof-gate-dashboard', title: 'Saved proof dashboard with accounts', evidence_needed: 'Not before proof.', recommendedLane: 'park', source_item_id: 'proof-gate-3', source_title: 'Nested proof gate' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
assert.equal(proofGateAliasResponse.status, 200);
|
||||||
|
const proofGateAlias = await proofGateAliasResponse.json();
|
||||||
|
const proofGateActive = proofGateAlias.ranked.find(item => item.id === 'nested-proof-gate-active');
|
||||||
|
assert.equal(proofGateAlias.ranked[0].id, 'nested-proof-gate-active');
|
||||||
|
assert.match(proofGateActive.nextStep, /source-traced proof script/);
|
||||||
|
assert.match(proofGateActive.evidenceQuestion, /without seeing a dashboard/);
|
||||||
|
assert.match(proofGateActive.successSignal, /thing not to build yet/);
|
||||||
|
assert.match(proofGateActive.killSignal, /workspace, account, or setup/);
|
||||||
|
assert.match(proofGateActive.description, /Proof steps: Read the active slice aloud; Ask what they would do next/);
|
||||||
|
assert.equal(proofGateAlias.brief.firstScreen.primaryAction, proofGateActive.nextStep);
|
||||||
|
assert.equal(proofGateAlias.brief.firstScreen.passSignal, proofGateActive.successSignal);
|
||||||
|
assert.equal(proofGateAlias.brief.firstScreen.stopSignal, proofGateActive.killSignal);
|
||||||
|
assert.equal(proofGateAlias.handoff.activeSlice.proof.successSignal, proofGateActive.successSignal);
|
||||||
|
assert.equal(proofGateAlias.handoff.readiness.status, 'ready');
|
||||||
|
assert.deepEqual(proofGateAlias.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));
|
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');
|
||||||
|
|||||||
@@ -1111,14 +1111,15 @@ function normalizeFeatureOption(item, index, fallbackId = 'feature', defaultSour
|
|||||||
const rawValue = typeof item === 'string' || typeof item === 'number' ? String(item) : '';
|
const rawValue = typeof item === 'string' || typeof item === 'number' ? String(item) : '';
|
||||||
const raw = rawValue ? { action: rawValue } : objectFrom(item);
|
const raw = rawValue ? { action: rawValue } : objectFrom(item);
|
||||||
const title = cleanText(raw.title || raw.name || raw.action || raw.move || raw.step || raw.task || raw.instruction || raw.nextMove || raw.next_move || raw.nextStep || raw.next_step || raw.recommendedNextStep || raw.recommended_next_step || raw.experiment || raw.testName || raw.test_name || raw.hypothesis || raw.label || raw.text || raw.content || raw.summary || '', 140);
|
const title = cleanText(raw.title || raw.name || raw.action || raw.move || raw.step || raw.task || raw.instruction || raw.nextMove || raw.next_move || raw.nextStep || raw.next_step || raw.recommendedNextStep || raw.recommended_next_step || raw.experiment || raw.testName || raw.test_name || raw.hypothesis || raw.label || raw.text || raw.content || raw.summary || '', 140);
|
||||||
const proofSteps = cleanTextList(raw.proofSteps || raw.proof_steps || raw.proof || raw.firstProof || raw.first_proof || raw.validationSteps || raw.validation_steps || raw.steps || raw.method, 5, 180);
|
const proofGate = objectFrom(raw.proofGate || raw.proof_gate || raw.validationGate || raw.validation_gate || raw.evidenceGate || raw.evidence_gate || raw.decisionGate || raw.decision_gate || raw.gate);
|
||||||
|
const proofSteps = cleanTextList(raw.proofSteps || raw.proof_steps || raw.proof || raw.firstProof || raw.first_proof || raw.validationSteps || raw.validation_steps || raw.steps || raw.method || proofGate.steps || proofGate.proofSteps || proofGate.proof_steps || proofGate.method, 5, 180);
|
||||||
const dependencies = cleanTextList(raw.dependencies || raw.blockedBy || raw.blocked_by, 5, 120);
|
const dependencies = cleanTextList(raw.dependencies || raw.blockedBy || raw.blocked_by, 5, 120);
|
||||||
const evidenceNeeded = cleanText(raw.evidenceNeeded || raw.evidence_needed || raw.evidenceToCollect || raw.evidence_to_collect || raw.evidence || raw.test || raw.proofQuestion || raw.proof_question || raw.evidenceQuestion || raw.evidence_question || raw.questionToAnswer || raw.question_to_answer || raw.question || raw.learningGoal || raw.learning_goal || '', 260);
|
const evidenceNeeded = cleanText(raw.evidenceNeeded || raw.evidence_needed || raw.evidenceToCollect || raw.evidence_to_collect || raw.evidence || raw.test || raw.proofQuestion || raw.proof_question || raw.evidenceQuestion || raw.evidence_question || raw.questionToAnswer || raw.question_to_answer || raw.question || raw.learningGoal || raw.learning_goal || proofGate.evidenceNeeded || proofGate.evidence_needed || proofGate.evidence || proofGate.question || proofGate.evidenceQuestion || proofGate.evidence_question || proofGate.learningGoal || proofGate.learning_goal || '', 260);
|
||||||
const userValue = cleanText(raw.userValue || raw.user_value || raw.value || raw.outcome || raw.why || raw.whyItMatters || raw.why_it_matters || raw.whyNow || raw.why_now, 260);
|
const userValue = cleanText(raw.userValue || raw.user_value || raw.value || raw.outcome || raw.why || raw.whyItMatters || raw.why_it_matters || raw.whyNow || raw.why_now, 260);
|
||||||
const risk = cleanText(raw.risk || raw.assumption || raw.unknown || raw.watchOut || raw.watch_out || '', 220);
|
const risk = cleanText(raw.risk || raw.assumption || raw.unknown || raw.watchOut || raw.watch_out || proofGate.risk || proofGate.assumption || '', 220);
|
||||||
const nextStep = cleanText(raw.nextStep || raw.next_step || raw.nextAction || raw.next_action || raw.firstStep || raw.first_step || raw.manualStep || raw.manual_step || raw.actionToTake || raw.action_to_take || raw.firstProofStep || raw.first_proof_step || raw.step || raw.task || raw.instruction || '', 260);
|
const nextStep = cleanText(raw.nextStep || raw.next_step || raw.nextAction || raw.next_action || raw.firstStep || raw.first_step || raw.manualStep || raw.manual_step || raw.actionToTake || raw.action_to_take || raw.firstProofStep || raw.first_proof_step || proofGate.nextStep || proofGate.next_step || proofGate.nextAction || proofGate.next_action || proofGate.firstStep || proofGate.first_step || proofGate.firstProofStep || proofGate.first_proof_step || raw.step || raw.task || raw.instruction || '', 260);
|
||||||
const successSignal = cleanText(raw.successSignal || raw.success_signal || raw.successCriteria || raw.success_criteria || raw.successMetric || raw.success_metric || raw.greenLight || raw.green_light || raw.greenFlag || raw.green_flag || raw.signalToSee || raw.signal_to_see || '', 260);
|
const successSignal = cleanText(raw.successSignal || raw.success_signal || raw.successCriteria || raw.success_criteria || raw.successMetric || raw.success_metric || raw.greenLight || raw.green_light || raw.greenFlag || raw.green_flag || raw.signalToSee || raw.signal_to_see || proofGate.successSignal || proofGate.success_signal || proofGate.successCriteria || proofGate.success_criteria || proofGate.greenLight || proofGate.green_light || proofGate.passSignal || proofGate.pass_signal || '', 260);
|
||||||
const killSignal = cleanText(raw.killSignal || raw.kill_signal || raw.stopSignal || raw.stop_signal || raw.redFlag || raw.red_flag || raw.failureSignal || raw.failure_signal || raw.cutIf || raw.cut_if || raw.stopIf || raw.stop_if || '', 260);
|
const killSignal = cleanText(raw.killSignal || raw.kill_signal || raw.stopSignal || raw.stop_signal || raw.redFlag || raw.red_flag || raw.failureSignal || raw.failure_signal || raw.cutIf || raw.cut_if || raw.stopIf || raw.stop_if || proofGate.killSignal || proofGate.kill_signal || proofGate.stopSignal || proofGate.stop_signal || proofGate.failureSignal || proofGate.failure_signal || proofGate.redFlag || proofGate.red_flag || proofGate.failSignal || proofGate.fail_signal || '', 260);
|
||||||
const rawLane = cleanText(raw.lane || '', 40);
|
const rawLane = cleanText(raw.lane || '', 40);
|
||||||
const laneLooksLikeHint = Boolean(normalizeLaneHint(rawLane));
|
const laneLooksLikeHint = Boolean(normalizeLaneHint(rawLane));
|
||||||
const sourceSection = cleanText(raw.sourceSection || raw.source_section || raw.section || raw.origin || (!laneLooksLikeHint ? rawLane : '') || defaultSourceSection, 80);
|
const sourceSection = cleanText(raw.sourceSection || raw.source_section || raw.section || raw.origin || (!laneLooksLikeHint ? rawLane : '') || defaultSourceSection, 80);
|
||||||
|
|||||||
Reference in New Issue
Block a user