mirror of
https://github.com/Ryder-Sun/Meldwork.git
synced 2026-11-07 06:56:03 -10:00
Include conflict outcomes in task graph review handoffs
Carry the accepted artifact and evidence references for each conflicting claim into review while preserving audience enforcement. Checks: task graph and human gate recovery tests.
This commit is contained in:
1 parent
f378bb3a27
commit
2cb640ca99
2 files changed
+36
No files matched your search
@@ -139,6 +139,14 @@ const taskGraphMethods = {
|
||||
if (['reviewer', 'arbiter'].includes(node.role)) {
|
||||
for (const conflict of this.unresolvedTaskGraphConflicts(controller.orchestration.collaboration)) {
|
||||
selected.push(conflict.entryId, ...conflict.refs)
|
||||
for (const state of cursor.nodeStates) {
|
||||
if (state.status === 'accepted' && state.entryIds.some(id => conflict.refs.includes(id))) {
|
||||
const outcomes = controller.orchestration.collaboration.entries.filter(entry => (
|
||||
state.entryIds.includes(entry.entryId) && ['artifact-ref', 'evidence-ref'].includes(entry.entryType)
|
||||
))
|
||||
selected.push(...outcomes.map(entry => entry.entryId))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return [...new Set(selected)]
|
||||
|
||||
@@ -314,6 +314,34 @@ test('task graph sends both conflicting claims to an arbiter even when only one
|
||||
assert.match(handoff.text, /Different position/)
|
||||
})
|
||||
|
||||
test('task graph includes outcome references for both sides of a conflict', () => {
|
||||
const first = graphNode({ nodeId: 'first', claimKey: 'shared' })
|
||||
const second = graphNode({ nodeId: 'second', agentKind: 'hermes', claimKey: 'shared' })
|
||||
const arbiter = graphNode({ nodeId: 'decision', role: 'arbiter', agentKind: 'codex', terminal: true,
|
||||
dependsOn: ['first', 'second'], inputNodeIds: ['first'] })
|
||||
const graph = createTaskGraph({ template: 'task-graph', nodes: [first, second, arbiter] })
|
||||
const controller = { runId: 'run', taskId: 'task', currentRound: 1, completedKinds: [], failedKinds: [],
|
||||
orchestration: { taskGraph: createTaskGraphCursor(graph), collaboration: emptyCollaborationState(), activeKinds: ['codex', 'hermes'] } }
|
||||
const runner = { ...collaborationMethods, ...taskGraphMethods,
|
||||
state: () => ({ messages: [] }),
|
||||
taskGraphVerifiedOutcomeRefs: node => ({ artifactIds: [`artifact-${node.nodeId}`], evidenceIds: [`evidence-${node.nodeId}`] }),
|
||||
checkpointOrchestration: (_group, target, updates) => Object.assign(target.orchestration, updates),
|
||||
checkpointTaskGraph: (_group, target, next) => { target.orchestration.taskGraph = next; return next },
|
||||
}
|
||||
for (const [node, text] of [[first, 'First position'], [second, 'Different position']]) {
|
||||
assert.equal(runner.applyTaskGraphAgentResult({}, controller, node,
|
||||
{ message: { content: text, trace: { status: 'completed', agentRunId: `${node.nodeId}-run` } } }), true)
|
||||
}
|
||||
const selected = new Set(runner.taskGraphSelectedEntryIds(controller, arbiter))
|
||||
const refs = controller.orchestration.collaboration.entries.filter(entry => selected.has(entry.entryId)
|
||||
&& ['artifact-ref', 'evidence-ref'].includes(entry.entryType)).flatMap(entry => entry.refs)
|
||||
assert.deepEqual(new Set(refs), new Set(['artifact-first', 'evidence-first', 'artifact-second', 'evidence-second']))
|
||||
const handoff = runner.prepareCollaborationPackage({ id: 'group' }, controller, ['codex', 'hermes'],
|
||||
'codex', '', { role: 'arbiter', selectedEntryIds: [...selected] })
|
||||
assert.equal(handoff.entries.length, selected.size)
|
||||
for (const ref of refs) assert.ok(handoff.text.includes(ref))
|
||||
})
|
||||
|
||||
test('task graph cannot accept an empty arbitration while conflicts remain', () => {
|
||||
const node = graphNode({ role: 'arbiter', agentKind: 'codex', terminal: true,
|
||||
acceptance: { requireConclusion: false, minArtifactRefs: 0, minEvidenceRefs: 0 } })
|
||||
|
||||
Reference in new issue
Block a user