@devflow-tools/benchmark 0.17.7 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -2
  3. package/dist/accuracy-command-options.d.ts +3 -0
  4. package/dist/accuracy-command-options.d.ts.map +1 -0
  5. package/dist/accuracy-command-options.js +17 -0
  6. package/dist/accuracy-command-options.js.map +1 -0
  7. package/dist/context-symbol-quality-command.d.ts +59 -0
  8. package/dist/context-symbol-quality-command.d.ts.map +1 -0
  9. package/dist/context-symbol-quality-command.js +482 -0
  10. package/dist/context-symbol-quality-command.js.map +1 -0
  11. package/dist/evaluation-bundle-builder.d.ts +48 -0
  12. package/dist/evaluation-bundle-builder.d.ts.map +1 -0
  13. package/dist/evaluation-bundle-builder.js +496 -0
  14. package/dist/evaluation-bundle-builder.js.map +1 -0
  15. package/dist/evaluation-bundle-command.d.ts +2 -0
  16. package/dist/evaluation-bundle-command.d.ts.map +1 -0
  17. package/dist/evaluation-bundle-command.js +15 -0
  18. package/dist/evaluation-bundle-command.js.map +1 -0
  19. package/dist/evaluation-bundle.d.ts +55 -0
  20. package/dist/evaluation-bundle.d.ts.map +1 -0
  21. package/dist/evaluation-bundle.js +272 -0
  22. package/dist/evaluation-bundle.js.map +1 -0
  23. package/dist/evaluation-run-state.d.ts +23 -0
  24. package/dist/evaluation-run-state.d.ts.map +1 -0
  25. package/dist/evaluation-run-state.js +115 -0
  26. package/dist/evaluation-run-state.js.map +1 -0
  27. package/dist/evidence-quality-metrics.d.ts +15 -0
  28. package/dist/evidence-quality-metrics.d.ts.map +1 -1
  29. package/dist/evidence-quality-metrics.js +51 -1
  30. package/dist/evidence-quality-metrics.js.map +1 -1
  31. package/dist/graders/deterministic.d.ts.map +1 -1
  32. package/dist/graders/deterministic.js +5 -3
  33. package/dist/graders/deterministic.js.map +1 -1
  34. package/dist/index.d.ts +15 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +12 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/release-quality-bundle-command.d.ts +3 -0
  39. package/dist/release-quality-bundle-command.d.ts.map +1 -0
  40. package/dist/release-quality-bundle-command.js +72 -0
  41. package/dist/release-quality-bundle-command.js.map +1 -0
  42. package/dist/release-quality-bundle-evaluator.d.ts +61 -0
  43. package/dist/release-quality-bundle-evaluator.d.ts.map +1 -0
  44. package/dist/release-quality-bundle-evaluator.js +321 -0
  45. package/dist/release-quality-bundle-evaluator.js.map +1 -0
  46. package/dist/release-quality-bundle-materializer.d.ts +79 -0
  47. package/dist/release-quality-bundle-materializer.d.ts.map +1 -0
  48. package/dist/release-quality-bundle-materializer.js +395 -0
  49. package/dist/release-quality-bundle-materializer.js.map +1 -0
  50. package/dist/release-quality-comparison.d.ts +34 -0
  51. package/dist/release-quality-comparison.d.ts.map +1 -0
  52. package/dist/release-quality-comparison.js +60 -0
  53. package/dist/release-quality-comparison.js.map +1 -0
  54. package/dist/release-quality-evaluation-command.d.ts +42 -0
  55. package/dist/release-quality-evaluation-command.d.ts.map +1 -0
  56. package/dist/release-quality-evaluation-command.js +91 -0
  57. package/dist/release-quality-evaluation-command.js.map +1 -0
  58. package/dist/release-quality-host-proof.d.ts +30 -0
  59. package/dist/release-quality-host-proof.d.ts.map +1 -0
  60. package/dist/release-quality-host-proof.js +109 -0
  61. package/dist/release-quality-host-proof.js.map +1 -0
  62. package/dist/release-quality-output-cleanup.d.ts +2 -0
  63. package/dist/release-quality-output-cleanup.d.ts.map +1 -0
  64. package/dist/release-quality-output-cleanup.js +18 -0
  65. package/dist/release-quality-output-cleanup.js.map +1 -0
  66. package/dist/release-quality-policy.d.ts +87 -0
  67. package/dist/release-quality-policy.d.ts.map +1 -0
  68. package/dist/release-quality-policy.js +179 -0
  69. package/dist/release-quality-policy.js.map +1 -0
  70. package/dist/release-quality-query-sampling.d.ts +36 -0
  71. package/dist/release-quality-query-sampling.d.ts.map +1 -0
  72. package/dist/release-quality-query-sampling.js +87 -0
  73. package/dist/release-quality-query-sampling.js.map +1 -0
  74. package/dist/release-quality-source-snapshot.d.ts +18 -0
  75. package/dist/release-quality-source-snapshot.d.ts.map +1 -0
  76. package/dist/release-quality-source-snapshot.js +46 -0
  77. package/dist/release-quality-source-snapshot.js.map +1 -0
  78. package/dist/retrieval-quality-corpus.d.ts +0 -1
  79. package/dist/retrieval-quality-corpus.d.ts.map +1 -1
  80. package/dist/retrieval-quality-corpus.js +1 -1
  81. package/dist/retrieval-quality-corpus.js.map +1 -1
  82. package/dist/retrieval-quality.d.ts.map +1 -1
  83. package/dist/retrieval-quality.js +29 -26
  84. package/dist/retrieval-quality.js.map +1 -1
  85. package/dist/run-accuracy-tests.js +82 -2
  86. package/dist/run-accuracy-tests.js.map +1 -1
  87. package/dist/suite-runner.js +1 -1
  88. package/dist/suite-runner.js.map +1 -1
  89. package/dist/unified-runtime-corpus.d.ts +64 -0
  90. package/dist/unified-runtime-corpus.d.ts.map +1 -0
  91. package/dist/unified-runtime-corpus.js +161 -0
  92. package/dist/unified-runtime-corpus.js.map +1 -0
  93. package/dist/unified-runtime-evaluation.d.ts +133 -0
  94. package/dist/unified-runtime-evaluation.d.ts.map +1 -0
  95. package/dist/unified-runtime-evaluation.js +388 -0
  96. package/dist/unified-runtime-evaluation.js.map +1 -0
  97. package/dist/unified-runtime-observation.d.ts +101 -0
  98. package/dist/unified-runtime-observation.d.ts.map +1 -0
  99. package/dist/unified-runtime-observation.js +2 -0
  100. package/dist/unified-runtime-observation.js.map +1 -0
  101. package/dist/unified-runtime-runner.d.ts +73 -0
  102. package/dist/unified-runtime-runner.d.ts.map +1 -0
  103. package/dist/unified-runtime-runner.js +620 -0
  104. package/dist/unified-runtime-runner.js.map +1 -0
  105. package/fixtures/evidence-runtime-corpus.json +0 -100
  106. package/fixtures/release-quality/bundles.json +1 -0
  107. package/fixtures/release-quality/calibration.json +602 -0
  108. package/fixtures/release-quality/ecc/corpus.json +257 -0
  109. package/fixtures/release-quality/ecc/input.json +62 -0
  110. package/fixtures/release-quality/llm-wiki/corpus.json +263 -0
  111. package/fixtures/release-quality/llm-wiki/input.json +72 -0
  112. package/fixtures/release-quality/mem0/corpus.json +288 -0
  113. package/fixtures/release-quality/mem0/input.json +68 -0
  114. package/fixtures/release-quality/projects.json +29 -0
  115. package/fixtures/release-quality/release-quality-policy.json +232 -0
  116. package/fixtures/release-quality/rsbuild-react/corpus.json +263 -0
  117. package/fixtures/release-quality/rsbuild-react/input.json +62 -0
  118. package/fixtures/retrieval-quality-corpus.json +7 -7
  119. package/fixtures/semantic-regex-inventory.json +3 -10
  120. package/fixtures/unified-runtime/baselines/2026-08-08.json +37 -0
  121. package/fixtures/unified-runtime/context.json +206 -0
  122. package/fixtures/unified-runtime/knowledge.json +224 -0
  123. package/fixtures/unified-runtime/memory.json +224 -0
  124. package/fixtures/unified-runtime/real-projects/rsbuild-react-2026-08-07/context.json +32 -0
  125. package/fixtures/unified-runtime/real-projects/rsbuild-react-2026-08-07/knowledge.json +32 -0
  126. package/fixtures/unified-runtime/real-projects/rsbuild-react-2026-08-07/memory.json +32 -0
  127. package/fixtures/unified-runtime/real-projects/rsbuild-react-2026-08-07/semantic.json +409 -0
  128. package/fixtures/unified-runtime/runs/rsbuild-react-2026-08-05.json +54 -0
  129. package/fixtures/unified-runtime/semantic.json +409 -0
  130. package/package.json +24 -6
@@ -0,0 +1,620 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join, resolve } from 'node:path';
6
+ import { createEngines } from '@devflow-tools/mcp-server/composition';
7
+ import { createDomainToolRegistry } from '@devflow-tools/mcp-server/retrieval';
8
+ import { openGlobalDevFlowDatabase } from '@devflow-tools/database';
9
+ import { createSemanticFacts, createRuntimeActivationSnapshotV1, semanticTextHash, stableRuntimeHash, } from '@devflow-tools/sdk';
10
+ import { compileChannelQueryPlan, resolveTaskSemanticContext, planDomainAction, } from '@devflow-tools/semantic-engine';
11
+ import { MemoryCommandService, MemoryStore } from '@devflow-tools/memory-engine';
12
+ import { reciprocalRankFusion, RetrievalCoordinator, RetrievalSessionRepository, } from '@devflow-tools/retrieval-engine';
13
+ import { emitSemanticControlLog } from '@devflow-tools/telemetry';
14
+ const RUNNER_VERSION = 'unified-runtime-runner.v4';
15
+ export async function runUnifiedRuntimeGold(corpus, options = {}) {
16
+ const projectRoot = options.projectRoot ?? resolve(import.meta.dirname, '../../..');
17
+ const runtime = options.runtime ?? runtimeIdentity(projectRoot);
18
+ const runStartedAt = performance.now();
19
+ emitSemanticControlLog({
20
+ event: 'benchmark.gold.loaded', identity: { projectRoot, sessionId: 'benchmark:unified-runtime' },
21
+ level: 'info', timestamp: Date.now(), data: {
22
+ datasetIds: corpus.datasetIds, labelSourceRevision: corpus.labelProvenance.sourceRevision,
23
+ semanticCount: corpus.semantic.length, contextCount: corpus.context.length,
24
+ memoryCount: corpus.memory.length, knowledgeCount: corpus.knowledge.length,
25
+ },
26
+ });
27
+ const activation = createRuntimeActivationSnapshotV1({
28
+ semantic: 'authoritative', retrieval: 'authoritative', memoryExtraction: 'deferred', knowledgeCompilation: 'deferred',
29
+ embeddingProfiles: {}, rolloutPolicyVersion: 'benchmark.v2', createdAt: Date.now(),
30
+ });
31
+ const engines = options.semanticExecutor ? undefined : await createEngines(projectRoot, { warmSymbolVectors: false });
32
+ try {
33
+ let runtimeRetrievalExecutor = options.retrievalExecutor;
34
+ if (!runtimeRetrievalExecutor && engines) {
35
+ runtimeRetrievalExecutor = (item, channel) => runRealRetrievalCase(item, channel, engines, projectRoot, activation);
36
+ }
37
+ const suiteIdentity = options.suiteIdentity ?? await resolveSuiteIdentity({
38
+ corpus, runtime, semanticExecutor: options.semanticExecutor,
39
+ retrievalExecutionSource: retrievalExecutionSource({
40
+ retrievalExecutor: Boolean(options.retrievalExecutor),
41
+ enginesAvailable: Boolean(engines),
42
+ }),
43
+ router: engines?.semanticRouter,
44
+ });
45
+ for (const [suite, identity] of Object.entries(suiteIdentity)) {
46
+ if ('status' in identity && identity.status === 'unavailable')
47
+ emitSemanticControlLog({
48
+ event: 'benchmark.capability.unavailable',
49
+ identity: { projectRoot, sessionId: 'benchmark:unified-runtime' },
50
+ level: 'warn', timestamp: Date.now(),
51
+ data: { suite, reasonCode: identity.reasonCode ?? 'capability_unavailable' },
52
+ });
53
+ }
54
+ const semantic = [];
55
+ const semanticStartedAt = performance.now();
56
+ for (const [index, item] of corpus.semantic.entries()) {
57
+ semantic.push(await executeSemanticCase(item, activation, options.semanticExecutor, engines?.semanticRouter));
58
+ if ((index + 1) % 10 === 0 || index + 1 === corpus.semantic.length)
59
+ options.observer?.({
60
+ stage: 'semantic', completed: index + 1, total: corpus.semantic.length,
61
+ elapsedMs: Math.round(performance.now() - semanticStartedAt),
62
+ });
63
+ }
64
+ const context = await runRetrievalCases(corpus.context, 'context', runtimeRetrievalExecutor, options.observer, semanticStartedAt);
65
+ const memory = await runRetrievalCases(corpus.memory, 'memory', runtimeRetrievalExecutor, options.observer, semanticStartedAt);
66
+ const knowledge = await runRetrievalCases(corpus.knowledge, 'knowledge', runtimeRetrievalExecutor, options.observer, semanticStartedAt);
67
+ const observation = {
68
+ schemaVersion: 'devflow.unified-runtime-observation.v4', capturedAt: Date.now(),
69
+ goldDatasetIds: corpus.datasetIds, runtime: { ...runtime }, suiteIdentity,
70
+ semantic, context, memory, knowledge,
71
+ };
72
+ emitSemanticControlLog({
73
+ event: 'benchmark.observation.captured', identity: { projectRoot, sessionId: 'benchmark:unified-runtime' },
74
+ level: 'info', timestamp: Date.now(), data: {
75
+ runtimeSourceHash: runtime.runtimeSourceHash, pluginRegistryHash: runtime.pluginRegistryHash,
76
+ semanticCount: semantic.length, contextCount: context.length, memoryCount: memory.length,
77
+ knowledgeCount: knowledge.length, latencyMs: Math.round(performance.now() - runStartedAt),
78
+ },
79
+ });
80
+ return observation;
81
+ }
82
+ finally {
83
+ closeIfPossible(engines?.memory);
84
+ closeIfPossible(engines?.knowledge);
85
+ closeIfPossible(engines?.telemetry);
86
+ }
87
+ }
88
+ async function executeSemanticCase(item, activation, executor, router) {
89
+ const startedAt = performance.now();
90
+ const context = executor ? await executor(item, activation) : await resolveTaskSemanticContext({
91
+ normalizedPrompt: item.prompt, identity: identityFor(item.id, item.slice.host), revision: 1, activation,
92
+ ...(router ? { router } : {}), ...(item.expected.targetAnchors ? { targetAnchors: item.expected.targetAnchors } : {}),
93
+ policy: { policyHash: 'benchmark:policy:v2', activeSkill: item.expected.activeSkill, budgets: { hookDeadlineMs: 3_000, contextTokens: 8_000, responseReserveTokens: 2_000, perChannelMs: { code: 1_500, memory: 800, knowledge: 1_500 } } },
94
+ }).then(result => result.context);
95
+ const semantic = context.facts;
96
+ const plan = item.expected.activeSkill ? planDomainAction({
97
+ identity: context.identity, taskRevisionHash: context.taskDefinitionHash, semanticContextHash: context.contextHash,
98
+ facts: semantic,
99
+ actionAuthority: context.actionAuthority,
100
+ objectKind: item.expected.domainAction?.tool === 'react_audit_performance'
101
+ ? 'performance' : item.expected.domainAction ? 'component' : undefined,
102
+ activeSkill: item.expected.activeSkill,
103
+ registry: createDomainToolRegistry(item.expected.activeSkill),
104
+ phase: 'final',
105
+ }) : undefined;
106
+ const fieldRefs = [
107
+ ...(semantic.intents.length > 0 ? semantic.intents.map(intent => `intent:${intent}`) : ['intent:unknown']),
108
+ ...(semantic.actions.length > 0 ? semantic.actions.map(action => `action:${action}`) : ['action:unknown']),
109
+ `memory:${semantic.memoryDirective}`,
110
+ ...(semantic.knowledgeNeeds.length > 0 ? semantic.knowledgeNeeds.map(need => `knowledge:${need.kind}`) : ['knowledge:none']),
111
+ `permission:${permissionRef(context.actionAuthority.mutation, semantic.conflicts.length > 0)}`,
112
+ ];
113
+ return {
114
+ caseId: item.id, datasetId: item.datasetId, runtimeContextHash: context.contextHash,
115
+ channelContextHashes: { context: context.contextHash, memory: context.contextHash, knowledge: context.contextHash },
116
+ fieldRefs, abstain: semantic.conflicts.length > 0,
117
+ mutationAuthorized: context.actionAuthority.mutation === 'authorized',
118
+ ...(plan ? { domainAction: {
119
+ ...(plan.selectedTool ? { tool: plan.selectedTool } : {}),
120
+ disposition: plan.status === 'selected' ? 'selected'
121
+ : plan.status === 'needs_condition_evidence' ? 'conditional_proposal' : 'abstained',
122
+ reasonCode: plan.reasonCode,
123
+ } } : {}),
124
+ terminalFalseSuccess: false,
125
+ latencyMs: Math.max(0, Math.round((performance.now() - startedAt) * 1000) / 1000),
126
+ };
127
+ }
128
+ async function runRetrievalCases(cases, channel, executor, observer, runStartedAt = performance.now()) {
129
+ if (executor)
130
+ return Promise.all(cases.map(item => executor(item, channel)));
131
+ const observations = [];
132
+ const root = mkdtempSync(join(tmpdir(), `devflow-unified-${channel}-`));
133
+ const database = openGlobalDevFlowDatabase(join(root, 'home'), { busyTimeoutMs: 500 });
134
+ try {
135
+ for (const [index, item] of cases.entries()) {
136
+ observations.push(await runRetrievalCase(item, channel, root, database));
137
+ if ((index + 1) % 10 === 0 || index + 1 === cases.length)
138
+ observer?.({
139
+ stage: channel, completed: index + 1, total: cases.length,
140
+ elapsedMs: Math.round(performance.now() - runStartedAt),
141
+ });
142
+ }
143
+ return observations;
144
+ }
145
+ finally {
146
+ database.close();
147
+ rmSync(root, { recursive: true, force: true });
148
+ }
149
+ }
150
+ async function runRetrievalCase(item, channel, root, database) {
151
+ const startedAt = performance.now();
152
+ const identity = identityFor(item.id, item.slice.host, root);
153
+ const context = buildBenchmarkRetrievalContext({
154
+ caseId: item.id,
155
+ prompt: item.prompt,
156
+ identity,
157
+ channel,
158
+ });
159
+ const producer = fixtureProducer(channel, item);
160
+ const empty = fixtureProducer(channel === 'context' ? 'memory' : 'context', item);
161
+ const stage = stageCapture();
162
+ const code = captureProducer(channel === 'context' ? producer : empty, stage);
163
+ const memory = captureProducer(channel === 'memory' ? producer : empty, stage);
164
+ const knowledge = captureProducer(channel === 'knowledge' ? producer : empty, stage);
165
+ const coordinator = new RetrievalCoordinator({
166
+ code, memory, knowledge, sessions: new RetrievalSessionRepository(database), taskRuntime: noOpTaskRuntime(),
167
+ });
168
+ let result = await coordinator.retrieve({ context, taskRevision: 1, tokenBudget: 8_000 });
169
+ let attempts = 1;
170
+ while (result.status === 'abstain' && attempts < item.expected.maxCycles) {
171
+ const next = await coordinator.retrieve({ context, taskRevision: 1, tokenBudget: 8_000 });
172
+ attempts += 1;
173
+ if (next.cycles.length <= result.cycles.length)
174
+ break;
175
+ result = next;
176
+ }
177
+ const selectedEvidence = (result.receipt.selectedEvidence ?? [])
178
+ .filter(candidate => candidate.channel === evidenceChannel(channel));
179
+ const selected = refsForRetrievalChannel(selectedEvidence, channel);
180
+ const sourceVersion = selectedEvidence.find(candidate => typeof candidate.payload.version === 'string')?.payload.version;
181
+ const episodePersisted = item.expected.explicitSave ? await executeExplicitSave(root, item.prompt, identity) : undefined;
182
+ const stages = retrievalStages(stage.candidates, result.receipt.rejectedRefs, channel);
183
+ return {
184
+ caseId: item.id, datasetId: item.datasetId, channel, runtimeContextHash: context.contextHash,
185
+ planRequirement: context.plan[evidenceChannel(channel)].requirement,
186
+ executionStatus: 'executed',
187
+ ...(item.expected.reasonCode ? { executionReasonCode: item.expected.reasonCode } : {}),
188
+ ...stages,
189
+ rankedEvidenceIds: selected,
190
+ cycles: result.cycles.length, duplicateOrNoGainStopObserved: result.cycles.length < 2 || (result.cycles.at(-1)?.noGainCount ?? 0) > 0,
191
+ latencyMs: Math.max(0, Math.round((performance.now() - startedAt) * 1000) / 1000),
192
+ rerankerBaselineIds: stages.fusionBaselineIds,
193
+ attributionSource: 'none',
194
+ attributionOutcomes: selected.map(() => 'unknown'),
195
+ verificationOutcomes: selected.map(() => 'unknown'),
196
+ ...(sourceVersion ? { sourceVersion } : {}),
197
+ ...(item.expected.temporalCorrect !== undefined ? { temporalCorrect: item.slice.availability === 'available' && selected.length > 0 } : {}),
198
+ ...(episodePersisted !== undefined ? { episodePersisted } : {}), terminalFalseSuccess: false,
199
+ };
200
+ }
201
+ export function buildBenchmarkRetrievalContext(input) {
202
+ const sourceHash = semanticTextHash(input.prompt);
203
+ const facts = createSemanticFacts({
204
+ sourceHash,
205
+ intents: [input.channel === 'context' ? 'understand' : input.channel],
206
+ actions: ['analyze'],
207
+ entities: [], targets: [], constraints: [], prohibitions: [], conditions: [],
208
+ memoryDirective: input.channel === 'memory' ? 'recall' : 'none',
209
+ knowledgeNeeds: input.channel === 'knowledge' ? [{ kind: 'overview', required: true }] : [],
210
+ evidence: [], conflicts: [], confidence: { overall: 1 },
211
+ });
212
+ const dispositions = ['code', 'memory', 'knowledge'].map(target => ({
213
+ channel: target,
214
+ requirement: target === evidenceChannel(input.channel) ? 'required'
215
+ : input.exclusive ? 'prohibited' : 'optional',
216
+ reasonCode: target === evidenceChannel(input.channel) ? 'benchmark_channel_required'
217
+ : input.exclusive ? 'benchmark_channel_prohibited' : 'benchmark_channel_optional',
218
+ evidenceIds: [],
219
+ }));
220
+ const authorityBody = {
221
+ mutation: 'not_requested',
222
+ targetAnchors: [], conditionEvidenceIds: [], authorityEvidenceIds: [],
223
+ reasonCode: 'benchmark_read_only',
224
+ };
225
+ const actionAuthority = { ...authorityBody, authorityHash: stableRuntimeHash(authorityBody) };
226
+ const plan = compileChannelQueryPlan({
227
+ identity: input.identity,
228
+ facts,
229
+ dispositions,
230
+ claims: [],
231
+ query: input.prompt,
232
+ createdAt: 1,
233
+ });
234
+ const contextBody = {
235
+ schemaVersion: 'semantic-execution-context',
236
+ identity: input.identity, facts, dispositions, actionAuthority, plan,
237
+ taskDefinitionHash: `definition:${input.caseId}`,
238
+ activationSnapshotHash: `activation:${input.caseId}`, embeddingProfiles: {}, scopeBindings: { project: { kind: 'project', id: input.identity.projectId }, session: { kind: 'session', id: input.identity.sessionId } },
239
+ mode: 'authoritative', createdAt: 1,
240
+ };
241
+ return { ...contextBody, contextHash: stableRuntimeHash(contextBody) };
242
+ }
243
+ export function restrictBenchmarkRetrievalChannel(context, channel, query) {
244
+ const facts = channel === 'memory' && context.facts.memoryDirective !== 'recall'
245
+ ? createSemanticFacts({ ...context.facts, memoryDirective: 'recall' })
246
+ : channel === 'knowledge' && context.facts.knowledgeNeeds.length === 0
247
+ ? createSemanticFacts({ ...context.facts, knowledgeNeeds: [{ kind: 'overview', required: true }] })
248
+ : context.facts;
249
+ const dispositions = ['code', 'memory', 'knowledge'].map(target => ({
250
+ channel: target,
251
+ requirement: target === evidenceChannel(channel) ? 'required' : 'prohibited',
252
+ reasonCode: target === evidenceChannel(channel)
253
+ ? 'benchmark_channel_required' : 'benchmark_channel_prohibited',
254
+ evidenceIds: [],
255
+ }));
256
+ const deterministicPlan = compileChannelQueryPlan({
257
+ identity: context.identity,
258
+ facts,
259
+ dispositions,
260
+ claims: [],
261
+ query,
262
+ createdAt: context.createdAt,
263
+ });
264
+ const selectedChannel = evidenceChannel(channel);
265
+ const preservesSampledPlan = context.plan[selectedChannel].requirement !== 'prohibited';
266
+ const code = selectedChannel === 'code'
267
+ ? requireBenchmarkChannel(context.plan.code, deterministicPlan.code)
268
+ : deterministicPlan.code;
269
+ const memory = selectedChannel === 'memory'
270
+ ? requireBenchmarkChannel(context.plan.memory, deterministicPlan.memory)
271
+ : deterministicPlan.memory;
272
+ const knowledge = selectedChannel === 'knowledge'
273
+ ? requireBenchmarkChannel(context.plan.knowledge, deterministicPlan.knowledge)
274
+ : deterministicPlan.knowledge;
275
+ const planBody = {
276
+ identity: context.identity,
277
+ sourceFactsHash: facts.factsHash,
278
+ code,
279
+ memory,
280
+ knowledge,
281
+ queryProposalIds: [code, memory, knowledge].flatMap(item => item.requirement === 'prohibited' ? [] : item.additions.flatMap(variant => variant.proposalId ?? [])),
282
+ generatedBy: preservesSampledPlan
283
+ ? context.plan.generatedBy
284
+ : deterministicPlan.generatedBy,
285
+ createdAt: context.plan.createdAt,
286
+ };
287
+ const plan = { ...planBody, planHash: stableRuntimeHash(planBody) };
288
+ const body = { ...context, facts, dispositions, plan };
289
+ return { ...body, contextHash: stableRuntimeHash({
290
+ schemaVersion: body.schemaVersion,
291
+ identity: body.identity,
292
+ facts: body.facts,
293
+ dispositions: body.dispositions,
294
+ actionAuthority: body.actionAuthority,
295
+ plan: body.plan,
296
+ activationSnapshotHash: body.activationSnapshotHash,
297
+ embeddingProfiles: body.embeddingProfiles,
298
+ scopeBindings: body.scopeBindings,
299
+ mode: body.mode,
300
+ createdAt: body.createdAt,
301
+ }) };
302
+ }
303
+ function requireBenchmarkChannel(source, deterministic) {
304
+ if (source.requirement === 'prohibited')
305
+ return deterministic;
306
+ return {
307
+ ...source,
308
+ requirement: 'required',
309
+ reasonCode: 'benchmark_channel_required',
310
+ evidenceIds: [],
311
+ };
312
+ }
313
+ async function runRealRetrievalCase(item, channel, engines, projectRoot, activation) {
314
+ const root = mkdtempSync(join(tmpdir(), `devflow-unified-real-${channel}-`));
315
+ const database = openGlobalDevFlowDatabase(join(root, 'home'), { busyTimeoutMs: 500 });
316
+ const startedAt = performance.now();
317
+ try {
318
+ const identity = identityFor(item.id, item.slice.host, projectRoot);
319
+ const resolved = await resolveTaskSemanticContext({
320
+ normalizedPrompt: item.prompt,
321
+ identity,
322
+ revision: 1,
323
+ activation,
324
+ router: engines.semanticRouter,
325
+ policy: {
326
+ policyHash: 'benchmark:policy:v2',
327
+ budgets: {
328
+ hookDeadlineMs: 3_000,
329
+ contextTokens: 8_000,
330
+ responseReserveTokens: 2_000,
331
+ perChannelMs: { code: 1_500, memory: 800, knowledge: 1_500 },
332
+ },
333
+ },
334
+ targetAnchors: [],
335
+ });
336
+ const context = resolved.context;
337
+ const stage = stageCapture();
338
+ const coordinator = new RetrievalCoordinator({
339
+ code: captureProducer(engines.codeEvidence, stage),
340
+ memory: captureProducer(engines.memoryQuery, stage),
341
+ knowledge: captureProducer(engines.knowledgeQuery, stage),
342
+ sessions: new RetrievalSessionRepository(database),
343
+ taskRuntime: noOpTaskRuntime(),
344
+ });
345
+ let result = await coordinator.retrieve({ context, taskRevision: 1, tokenBudget: 8_000 });
346
+ let attempts = 1;
347
+ while (result.status === 'abstain' && attempts < item.expected.maxCycles) {
348
+ const next = await coordinator.retrieve({ context, taskRevision: 1, tokenBudget: 8_000 });
349
+ attempts += 1;
350
+ if (next.cycles.length <= result.cycles.length)
351
+ break;
352
+ result = next;
353
+ }
354
+ const selectedEvidence = (result.receipt.selectedEvidence ?? [])
355
+ .filter(candidate => candidate.channel === evidenceChannel(channel));
356
+ const selected = refsForRetrievalChannel(selectedEvidence, channel);
357
+ const sourceVersion = selectedEvidence.find(candidate => typeof candidate.payload.version === 'string')?.payload.version;
358
+ const episodePersisted = item.expected.explicitSave
359
+ ? await executeExplicitSave(root, item.prompt, identity)
360
+ : undefined;
361
+ const stages = retrievalStages(stage.candidates, result.receipt.rejectedRefs, channel);
362
+ const execution = retrievalExecution(context, result.receipt, channel);
363
+ return {
364
+ caseId: item.id, datasetId: item.datasetId, channel,
365
+ runtimeContextHash: context.contextHash,
366
+ ...execution,
367
+ ...stages,
368
+ rankedEvidenceIds: selected,
369
+ cycles: result.cycles.length,
370
+ duplicateOrNoGainStopObserved: result.cycles.length < 2 || (result.cycles.at(-1)?.noGainCount ?? 0) > 0,
371
+ latencyMs: Math.max(0, Math.round((performance.now() - startedAt) * 1000) / 1000),
372
+ rerankerBaselineIds: stages.fusionBaselineIds,
373
+ attributionSource: 'none',
374
+ attributionOutcomes: selected.map(() => 'unknown'),
375
+ verificationOutcomes: selected.map(() => 'unknown'),
376
+ ...(sourceVersion ? { sourceVersion } : {}),
377
+ ...(episodePersisted !== undefined ? { episodePersisted } : {}),
378
+ terminalFalseSuccess: false,
379
+ };
380
+ }
381
+ catch (error) {
382
+ return {
383
+ caseId: item.id, datasetId: item.datasetId, channel,
384
+ runtimeContextHash: semanticTextHash(item.prompt),
385
+ planRequirement: 'required',
386
+ executionStatus: 'failed', executionReasonCode: 'runtime_retrieval_exception',
387
+ candidateEvidenceIds: [],
388
+ eligibilityRejectedEvidenceIds: [], rankedEvidenceIds: [], rejectedEvidenceIds: [],
389
+ rejectionReasonCounts: {}, cycles: 1, duplicateOrNoGainStopObserved: true,
390
+ latencyMs: Math.max(0, Math.round((performance.now() - startedAt) * 1000) / 1000),
391
+ rerankerBaselineIds: [], attributionSource: 'none', attributionOutcomes: [],
392
+ verificationOutcomes: [], terminalFalseSuccess: false,
393
+ };
394
+ }
395
+ finally {
396
+ database.close();
397
+ rmSync(root, { recursive: true, force: true });
398
+ }
399
+ }
400
+ function retrievalExecution(context, receipt, channel) {
401
+ const target = evidenceChannel(channel);
402
+ if (context.plan[target].requirement === 'prohibited') {
403
+ return { planRequirement: 'prohibited', executionStatus: 'blocked', executionReasonCode: 'channel_prohibited' };
404
+ }
405
+ const originalLegs = (receipt.legs ?? [])
406
+ .filter(outcome => outcome.channel === target && outcome.queryVariant.kind === 'original');
407
+ if (originalLegs.length === 0) {
408
+ return { planRequirement: context.plan[target].requirement, executionStatus: 'failed', executionReasonCode: 'original_leg_missing' };
409
+ }
410
+ const status = originalLegs[0].status;
411
+ return {
412
+ planRequirement: context.plan[target].requirement,
413
+ executionStatus: status,
414
+ executionReasonCode: originalLegs.find(outcome => outcome.reasonCode)?.reasonCode
415
+ ?? (status === 'executed' ? undefined : `original_leg_${status}`),
416
+ };
417
+ }
418
+ const ELIGIBILITY_REJECTION_REASONS = new Set([
419
+ 'producer_channel_mismatch', 'scope_mismatch', 'permission_denied', 'permission_unknown',
420
+ 'source_not_ready', 'expired', 'authority_missing', 'authority_below_threshold',
421
+ 'profile_unbound', 'profile_missing', 'profile_mismatch',
422
+ ]);
423
+ export function stageCapture() {
424
+ return { candidates: [], outputs: [] };
425
+ }
426
+ export function captureProducer(producer, stage) {
427
+ return {
428
+ ...producer,
429
+ async search(context, request) {
430
+ const result = await producer.search(context, request);
431
+ stage.candidates.push(...result.candidates);
432
+ const diagnostic = producer.getLastVectorCandidateRefs?.();
433
+ stage.outputs.push({ result, ...(diagnostic ? { vectorCandidateRefs: diagnostic } : {}) });
434
+ return result;
435
+ },
436
+ };
437
+ }
438
+ export function retrievalStages(candidates, rejected, channel) {
439
+ const channelCandidates = candidates.filter(candidate => candidate.channel === evidenceChannel(channel));
440
+ const channelRefs = new Set(channelCandidates.map(candidate => candidate.stableRef));
441
+ const channelRejected = rejected.filter(item => channelRefs.has(item.ref));
442
+ const eligibilityRejected = new Set(channelRejected
443
+ .filter(item => ELIGIBILITY_REJECTION_REASONS.has(item.reason))
444
+ .map(item => item.ref));
445
+ const eligible = channelCandidates.filter(candidate => !eligibilityRejected.has(candidate.stableRef));
446
+ return {
447
+ candidateEvidenceIds: uniqueRefs(channelCandidates.map(candidate => candidate.stableRef)),
448
+ eligibilityRejectedEvidenceIds: [...eligibilityRejected].sort(),
449
+ rejectedEvidenceIds: uniqueRefs(channelRejected.map(item => item.ref)),
450
+ rejectionReasonCounts: channelRejected.reduce((counts, item) => {
451
+ counts[item.reason] = (counts[item.reason] ?? 0) + 1;
452
+ return counts;
453
+ }, {}),
454
+ fusionBaselineIds: reciprocalRankFusion(eligible).map(item => item.candidate.stableRef),
455
+ };
456
+ }
457
+ export function refsForRetrievalChannel(evidence, channel) {
458
+ const expected = evidenceChannel(channel);
459
+ return evidence.filter(item => item.channel === expected).map(item => item.stableRef);
460
+ }
461
+ export function rankedEvidenceRefs(receipt, channel) {
462
+ const expected = evidenceChannel(channel);
463
+ return [...(receipt.evidenceReceipts ?? [])]
464
+ .filter(item => item.channel === expected && item.stage === 'ranked' && Number.isSafeInteger(item.rank))
465
+ .sort((left, right) => left.rank - right.rank || left.stableRef.localeCompare(right.stableRef))
466
+ .map(item => item.stableRef)
467
+ .filter((ref, index, refs) => refs.indexOf(ref) === index);
468
+ }
469
+ function evidenceChannel(channel) {
470
+ return channel === 'context' ? 'code' : channel;
471
+ }
472
+ function uniqueRefs(refs) {
473
+ return [...new Set(refs)].sort();
474
+ }
475
+ function fixtureProducer(channel, item) {
476
+ return {
477
+ async search(context, request) {
478
+ const available = item.slice.availability === 'available' ? 'available' : 'unavailable';
479
+ const candidates = available === 'available' ? item.expected.evidenceIds.map((stableRef, index) => candidateFor(channel, stableRef, index, context, item.expected.sourceVersion)) : [];
480
+ const body = {
481
+ schemaVersion: 'evidence-receipt.v1',
482
+ receiptId: `${channel}:${stableRuntimeHash({ context: context.contextHash, request: request.signatureHash }).slice(0, 20)}`,
483
+ parentReceiptIds: [request.receiptId],
484
+ taskContextHash: context.contextHash,
485
+ factsHash: context.facts.factsHash,
486
+ planHash: context.plan.planHash,
487
+ activationSnapshotHash: context.activationSnapshotHash,
488
+ channel: channel === 'context' ? 'code' : channel,
489
+ availability: available,
490
+ selectedRefs: [],
491
+ rejectedRefs: [],
492
+ gaps: [],
493
+ createdAt: Date.now(),
494
+ };
495
+ return { availability: available, candidates, gaps: [], receipt: { ...body, receiptHash: stableRuntimeHash(body) } };
496
+ },
497
+ };
498
+ }
499
+ function candidateFor(channel, stableRef, index, context, sourceVersion) {
500
+ const actualChannel = channel === 'context' ? 'code' : channel;
501
+ const payload = channel === 'context' ? { path: stableRef.replace(/^code:/u, '') } : channel === 'knowledge' ? { id: stableRef, source: stableRef, title: stableRef, excerpt: stableRef, ...(sourceVersion ? { version: sourceVersion } : {}), applicability: ['kind:overview'] } : { id: stableRef, title: stableRef, content: stableRef, type: 'project_convention', applicability: ['fixture'] };
502
+ return {
503
+ stableRef, channel: actualChannel, strength: actualChannel === 'code' ? 'strong' : 'supporting', rank: index + 1, score: 1 - index * 0.01,
504
+ evidence: { ref: stableRef, sourceId: stableRef, sourceRevision: 'fixture.v2', producer: 'benchmark-fixture-producer', producerVersion: RUNNER_VERSION, contentHash: stableRuntimeHash(payload), parentRefs: [] },
505
+ payload, freshness: { current: true, checkedAt: Date.now() }, contributingLegs: [{ leg: `${actualChannel}:fixture`, rank: index + 1, score: 1 - index * 0.01 }],
506
+ eligibility: { scope: context.scopeBindings.project, permission: 'allowed', sourceReady: true }, estimatedTokens: 16,
507
+ };
508
+ }
509
+ export function noOpTaskRuntime() {
510
+ return { sessionOpened() { }, cycleCompleted() { } };
511
+ }
512
+ async function executeExplicitSave(root, prompt, identity) {
513
+ const projectIdentity = {
514
+ projectId: identity.projectId,
515
+ memoryNamespace: `memory:${identity.projectId}`,
516
+ };
517
+ const store = new MemoryStore(root, undefined, projectIdentity);
518
+ try {
519
+ const result = await new MemoryCommandService(root, store, projectIdentity).commitExplicitEpisode({
520
+ content: prompt,
521
+ actorId: 'actor:benchmark-runner',
522
+ sessionId: identity.sessionId,
523
+ turnId: identity.turnId,
524
+ sourceMessageId: identity.requestId,
525
+ });
526
+ return result.episode.episodeId.length > 0;
527
+ }
528
+ finally {
529
+ store.close();
530
+ }
531
+ }
532
+ export function identityFor(caseId, host, projectRoot = '/benchmark', projectId = 'project:benchmark-runtime') {
533
+ return { projectRoot, projectId, hostId: host, sessionId: `session:${caseId}`, turnId: `turn:${caseId}`, requestId: `request:${caseId}`, executionId: `execution:${caseId}` };
534
+ }
535
+ function permissionRef(value, _conflicted) {
536
+ return value;
537
+ }
538
+ export function runtimeIdentity(root, sourceRoot = resolve(import.meta.dirname, '../../..')) {
539
+ // Runtime identity belongs to the DevFlow distribution under test, while
540
+ // projectRoot may point at an external initialized host project.
541
+ const packageJson = JSON.parse(readFileSync(resolve(sourceRoot, 'packages/devflow/package.json'), 'utf8'));
542
+ const pluginRegistry = readFileSync(resolve(sourceRoot, 'packages/devflow/plugin-registry.json'), 'utf8');
543
+ const files = gitOutput(sourceRoot, ['ls-files', '-co', '--exclude-standard'])
544
+ .split('\n')
545
+ .filter(runtimeSourceFile)
546
+ .sort();
547
+ const sourceFiles = files.map(path => [
548
+ path,
549
+ createHash('sha256').update(readFileSync(resolve(sourceRoot, path))).digest('hex'),
550
+ ]);
551
+ return {
552
+ packageVersion: packageJson.version,
553
+ pluginRegistryHash: stableRuntimeHash(pluginRegistry),
554
+ runtimeSourceHash: stableRuntimeHash({ packageVersion: packageJson.version, sourceFiles }),
555
+ runnerVersion: RUNNER_VERSION,
556
+ };
557
+ }
558
+ function gitOutput(root, args) {
559
+ try {
560
+ return execFileSync('git', ['-C', root, ...args], {
561
+ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 10_000,
562
+ maxBuffer: 16 * 1024 * 1024,
563
+ }).trim();
564
+ }
565
+ catch {
566
+ return '';
567
+ }
568
+ }
569
+ function runtimeSourceFile(path) {
570
+ if (path.includes('/dist/') || path.includes('/fixtures/') || path.includes('/__tests__/'))
571
+ return false;
572
+ return path === 'package.json'
573
+ || path === 'package-lock.json'
574
+ || path === 'packages/devflow/plugin-registry.json'
575
+ || /^apps\/[^/]+\/(?:package\.json|src\/)/u.test(path)
576
+ || /^packages\/[^/]+\/(?:package\.json|src\/)/u.test(path)
577
+ || path.startsWith('scripts/');
578
+ }
579
+ async function resolveSuiteIdentity(input) {
580
+ const semanticCapability = input.semanticExecutor
581
+ ? {
582
+ status: 'executed', resolver: 'host_sampling',
583
+ profileHash: stableRuntimeHash({ executor: 'injected', runnerVersion: input.runtime.runnerVersion }),
584
+ }
585
+ : input.router && await input.router.warmup()
586
+ ? {
587
+ status: 'executed', resolver: 'embedding',
588
+ profileHash: stableRuntimeHash({
589
+ modelId: input.router.modelId,
590
+ modelRevision: input.router.modelRevision,
591
+ thresholdVersion: input.router.thresholdVersion,
592
+ }),
593
+ }
594
+ : { status: 'unavailable', resolver: 'embedding', reasonCode: 'embedding_unavailable' };
595
+ return {
596
+ deterministicSafety: {
597
+ runtimeSourceHash: input.runtime.runtimeSourceHash,
598
+ runnerVersion: input.runtime.runnerVersion,
599
+ },
600
+ semanticCapability,
601
+ retrievalExecution: {
602
+ status: 'executed', source: input.retrievalExecutionSource,
603
+ datasetIds: [input.corpus.datasetIds.context, input.corpus.datasetIds.memory, input.corpus.datasetIds.knowledge],
604
+ },
605
+ candidateGeneration: {
606
+ status: 'unavailable', source: 'runtime_index',
607
+ reasonCode: input.retrievalExecutionSource === 'real_project'
608
+ ? 'evaluation_bundle_runner_required' : 'fixture_seeded_only',
609
+ },
610
+ externalReplay: { status: 'unavailable', reasonCode: 'external_replay_not_provided' },
611
+ };
612
+ }
613
+ export function retrievalExecutionSource(input) {
614
+ return !input.retrievalExecutor && input.enginesAvailable ? 'real_project' : 'fixture_seeded';
615
+ }
616
+ function closeIfPossible(value) {
617
+ if (value && typeof value.close === 'function')
618
+ value.close();
619
+ }
620
+ //# sourceMappingURL=unified-runtime-runner.js.map