Add active slice handoff contract

This commit is contained in:
OpenClaw Bot
2026-05-27 16:05:12 +02:00
parent 92a086824c
commit 460f088a8b
3 changed files with 57 additions and 3 deletions
+47 -2
View File
@@ -1396,7 +1396,41 @@ function handoffReadinessFor({ ranked = [], provenance = {}, warnings = [], expe
};
}
function copyableHandoffText({ ranked = [], provenance = {}, decisionContext = {}, readiness = {} }) {
function activeSliceFor({ ranked = [], provenance = {}, readiness = {} }) {
const active = ranked.find(item => item.lane?.id === 'do') || ranked.find(item => item.lane?.id === 'test') || ranked[0] || null;
const heldBack = ranked.filter(item => item.id !== active?.id && ['test', 'defer', 'park'].includes(item.lane?.id)).slice(0, 4);
if (!active) return null;
return {
schema: 'ranker-active-slice-v1',
item: {
id: active.id,
title: active.title,
lane: active.lane?.id || 'do',
laneLabel: active.lane?.label || 'Do first',
reason: reasonFor(active),
},
proof: {
nextStep: nextStepFor(active),
evidenceQuestion: evidenceQuestionFor(active),
successSignal: successSignalFor(active),
killSignal: killSignalFor(active),
},
source: {
artifactId: provenance?.artifactId || '',
conceptMapId: provenance?.conceptMapId || '',
snapshotTitle: provenance?.snapshotTitle || '',
sourceSection: active.provenance?.sourceSection || '',
sourceId: active.provenance?.sourceId || '',
sourceTitle: active.provenance?.sourceTitle || '',
sourceQuote: active.provenance?.sourceQuote || '',
},
notNow: heldBack.map(item => ({ id: item.id, title: item.title, lane: item.lane?.id || 'defer', reason: reasonFor(item) })),
readinessStatus: readiness?.status || '',
rule: 'Only this active slice is build-ready. Do not promote Validate next / Defer / Park items until evidence changes and Ranker is rerun.',
};
}
function copyableHandoffText({ ranked = [], provenance = {}, decisionContext = {}, readiness = {}, activeSlice = null }) {
const lanes = [
['do', 'Do first'],
['test', 'Validate next'],
@@ -1438,11 +1472,20 @@ function copyableHandoffText({ ranked = [], provenance = {}, decisionContext = {
'',
];
});
const activeSliceLines = activeSlice ? [
'## Active slice',
`- Move: ${activeSlice.item.title}`,
`- Proof: ${activeSlice.proof.nextStep}`,
`- Evidence question: ${activeSlice.proof.evidenceQuestion}`,
activeSlice.source.sourceSection ? `- Source: ${[activeSlice.source.sourceSection, activeSlice.source.sourceId].filter(Boolean).join(' · ')}` : '',
activeSlice.notNow.length ? `- Do not start yet: ${activeSlice.notNow.map(item => item.title).join('; ')}` : '',
].filter(Boolean).join('\n') : '';
return [
'# Ranker build-order handoff',
sourceLine ? `Source: ${sourceLine}` : '',
sourceContextLine,
readiness?.status ? `Readiness: ${readiness.status}${readiness.summary || ''}` : '',
activeSliceLines,
contextLines.length ? ['## Carried context', ...contextLines.map(item => `- ${item}`)].join('\n') : '',
...itemLines,
'Rule: only the Do first item is active. Re-rank after evidence changes; do not quietly turn this into a workspace/dashboard backlog.',
@@ -1479,6 +1522,7 @@ function createHandoffContract({ ranked, provenance, decisionContext }) {
});
const uniqueWarnings = [...new Set(warnings)];
const readiness = handoffReadinessFor({ ranked, provenance, warnings: uniqueWarnings, expectsSourceTrace });
const activeSlice = activeSliceFor({ ranked, provenance, readiness });
return {
schema: 'rank-feedback-result-v1',
@@ -1503,7 +1547,8 @@ function createHandoffContract({ ranked, provenance, decisionContext }) {
itemTrace,
warnings: uniqueWarnings,
readiness,
copyableText: copyableHandoffText({ ranked, provenance, decisionContext, readiness }),
activeSlice,
copyableText: copyableHandoffText({ ranked, provenance, decisionContext, readiness, activeSlice }),
};
}