mirror of
https://github.com/Ryder-Sun/Meldwork.git
synced 2026-11-07 06:56:03 -10:00
Provide verified outcomes to task graph reviewers
Materialize audience-approved text artifacts and evidence summaries with bounded, redacted content so isolated reviews can inspect their supporting outcomes. Checks: task graph and human gate recovery tests; workspace reviewer integration test.
This commit is contained in:
1 parent
2cb640ca99
commit
4a9fa31812
2 files changed
+58
No files matched your search
@@ -167,6 +167,35 @@ const taskGraphMethods = {
|
||||
].join('\n')
|
||||
},
|
||||
|
||||
taskGraphReviewOutcomeText(entries) {
|
||||
const lines = []
|
||||
let remaining = 24000
|
||||
for (const entry of entries) {
|
||||
if (!['artifact-ref', 'evidence-ref'].includes(entry.entryType)) continue
|
||||
const id = entry.refs?.[0]
|
||||
let label
|
||||
let raw
|
||||
if (entry.entryType === 'artifact-ref') {
|
||||
const identity = this.v4ArtifactIdentity(id)
|
||||
label = `Artifact ${id}`
|
||||
raw = identity.artifact.contentRef?.mediaType === 'text/plain'
|
||||
? identity.content : '[Non-text artifact; content unavailable in this handoff.]'
|
||||
} else {
|
||||
const evidence = this.v4EvidenceRecord(id)
|
||||
label = `Evidence ${id} (${evidence.kind}, ${evidence.level})`
|
||||
raw = evidence.summary
|
||||
}
|
||||
const limit = Math.max(0, Math.min(6000, remaining))
|
||||
if (!limit) { lines.push('[Additional outcome content truncated.]'); break }
|
||||
const content = publicCollaborationText(raw || '', limit + 1)
|
||||
const truncated = content.length > limit
|
||||
const shown = content.slice(0, limit)
|
||||
lines.push(`${label}: ${shown}${truncated ? ' [Content truncated.]' : ''}`)
|
||||
remaining -= shown.length
|
||||
}
|
||||
return lines.length ? `Verified outcome content:\n${lines.join('\n')}\nDo not assume truncated or unavailable content was reviewed.` : ''
|
||||
},
|
||||
|
||||
checkpointTaskGraph(group, controller, cursorInput, options = {}) {
|
||||
let taskGraph = parseTaskGraphCursor(cursorInput)
|
||||
taskGraph = parseTaskGraphCursor({
|
||||
@@ -453,6 +482,10 @@ const taskGraphMethods = {
|
||||
throw new Error('LOCAL_WORKFLOW_INPUT_UNAVAILABLE')
|
||||
}
|
||||
const isolated = ['reviewer', 'arbiter'].includes(node.role)
|
||||
if (isolated) {
|
||||
const outcomes = this.taskGraphReviewOutcomeText(collaborationPackage.entries)
|
||||
if (outcomes) collaborationPackage.text += `\n${outcomes}`
|
||||
}
|
||||
const attachments = node.role === 'primary'
|
||||
&& !controller.orchestration.attachmentRecipients.includes(node.agentKind)
|
||||
? context.rootAttachments.map(attachment => attachment.path)
|
||||
|
||||
@@ -342,6 +342,29 @@ test('task graph includes outcome references for both sides of a conflict', () =
|
||||
for (const ref of refs) assert.ok(handoff.text.includes(ref))
|
||||
})
|
||||
|
||||
test('task graph review materializes bounded verified outcome content without exposing secrets', () => {
|
||||
const runner = { ...taskGraphMethods,
|
||||
v4ArtifactIdentity: id => {
|
||||
assert.equal(id, 'artifact-one')
|
||||
return { artifact: { contentRef: { mediaType: 'text/plain' } }, content: `Result sk-test-12345678901234567890 ${'x'.repeat(7000)}` }
|
||||
},
|
||||
v4EvidenceRecord: id => {
|
||||
assert.equal(id, 'evidence-one')
|
||||
return { kind: 'test-result', level: 'observed', summary: 'Verification succeeded' }
|
||||
},
|
||||
}
|
||||
const text = runner.taskGraphReviewOutcomeText([
|
||||
{ entryType: 'artifact-ref', refs: ['artifact-one'] },
|
||||
{ entryType: 'evidence-ref', refs: ['evidence-one'] },
|
||||
])
|
||||
assert.match(text, /Result/)
|
||||
assert.match(text, /Verification succeeded/)
|
||||
assert.match(text, /truncated/i)
|
||||
assert.doesNotMatch(text, /sk-test-12345678901234567890/)
|
||||
assert.ok(text.length < 10000)
|
||||
assert.throws(() => runner.taskGraphReviewOutcomeText([{ entryType: 'artifact-ref', refs: ['missing'] }]))
|
||||
})
|
||||
|
||||
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 } })
|
||||
@@ -1381,6 +1404,8 @@ test('automatic Primary Reviewer Arbiter flow uses selective typed collaboration
|
||||
assert.match(calls[0].prompt, /Role: primary/)
|
||||
assert.match(calls[0].prompt, /Selected blackboard entries: \(none\)/)
|
||||
assert.match(calls[1].prompt, /Role: reviewer/)
|
||||
assert.match(calls[1].prompt, /Verified outcome content:/)
|
||||
assert.match(calls[1].prompt, /Evidence .*\(.*\)/)
|
||||
assert.match(calls[1].prompt, /The release is ready after tests\./)
|
||||
assert.match(calls[2].prompt, /Role: arbiter/)
|
||||
assert.match(calls[2].prompt, /\[conflict\]/)
|
||||
|
||||
Reference in new issue
Block a user