Conversation
… dataArtifacts
RawExecutionDriver destructured only writeResource from createResourceWriter()
and createFileWriter from createFileWriterFactory(), ignoring the getHandles()
function from both. After method execution, it relied on result.dataHandles
from the method's return value, which is undefined for extension models that
return {}.
This caused all extension models using the raw driver to produce empty
dataArtifacts in their run output, breaking the CLI output view,
method-summary reports, and output log artifact lookup. The data itself was
persisted correctly to disk (writeResource works in-process), but the output
metadata didn't reference it.
The fix destructures getHandles from both writer factories and uses the
combined writer handles as a fallback when result.dataHandles is empty.
Built-in models that return explicit dataHandles are unaffected — the
fallback only triggers when the method returns no handles.
Fixes #907
Co-authored-by: Magistr <umag@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
Clean, focused bug fix. The change correctly wires up getHandles() from both createResourceWriter and createFileWriterFactory, using the collected writer handles as a fallback when result.dataHandles is empty. The fallback logic (result.dataHandles?.length ? result.dataHandles : writerHandles) preserves backward compatibility for built-in models that return explicit handles.
Blocking Issues
None.
Suggestions
None — this is a well-scoped fix with good test coverage (3 tests covering the fix, backward compat, and empty case). The test mocking approach is consistent with other domain-layer tests in the repo.
DDD: RawExecutionDriver correctly acts as a domain service orchestrating writer factories and method execution. The fix uses existing domain collaborator APIs (getHandles) rather than introducing new coupling.
CLAUDE.md: License header present, test file co-located, naming convention followed, no any types, no libswamp boundary violations.
There was a problem hiding this comment.
Adversarial Review
Medium
-
src/domain/drivers/raw_execution_driver.ts:150-152—dataHandles: []treated same asundefinedThe fallback condition
result.dataHandles?.length ? result.dataHandles : writerHandlestreats an explicit empty array[]identically toundefined/missing. If a method deliberately returns{ dataHandles: [] }to signal "I intentionally produced zero outputs" while also callingwriteResourceas a side effect (e.g. writing a tombstone or marker that shouldn't appear in outputs), the driver would incorrectly surface the writer handles.In practice this doesn't happen today — methods that return
dataHandles: []in the codebase are test stubs that don't callwriteResource, and real extension models return{}(no property at all). But the semantic distinction between "I have no outputs" vs "I didn't track outputs" is collapsed. A comment clarifying the intent would prevent future confusion, though this is not blocking since no current code path triggers the issue. -
src/domain/drivers/raw_execution_driver_test.ts:161-175— first test assertsoutputs.length > 0but the mocksave()never produces a real handleThe
createMockDataRepo().save()returns{ version: 1 }but the test's mockwriteResourcecall at line 164 goes throughcreateResourceWriterwhich calls the realDataWriter.writeText(). Since the mock repo'sallocateVersionreturnscontentPath: "/tmp/mock", this will attempt to write to/tmp/mockon disk. If/tmp/mockis not writable or doesn't exist as a directory parent, the test would fail with an OS error rather than a clear assertion failure. This is a test fragility issue, not a production concern. The test works today but is implicitly dependent on/tmpbeing writable.
Low
-
src/domain/drivers/raw_execution_driver.ts:146-149— writerHandles always computed even when unusedWhen
result.dataHandlesis non-empty, thegetResourceHandles()andgetFileHandles()calls (array copies via spread) are wasted work. This is negligible overhead — just two small array allocations — but if performance profiling ever flags this hot path, the calls could be deferred behind the condition check.
Verdict
PASS — The fix is correct for its stated purpose. The fallback logic properly handles the extension model case (returns {}) and preserves backward compatibility for built-in models (returns populated dataHandles). The data flow through processDriverOutputs back in method_execution_service.ts correctly picks up the driver's outputs. The edge case in Medium #1 is theoretical and doesn't affect any current code path.
Summary
Fixes #907
RawExecutionDriverignoredgetHandles()from bothcreateResourceWriterandcreateFileWriterFactory. After method execution, it relied onresult.dataHandlesfrom the method's return value — which isundefinedfor extension models that return{}.Impact: All extension models using the raw driver produced empty
dataArtifactsin their run output. This broke:output_logs.tsfilters ondataArtifacts)The data itself was persisted correctly to disk (
writeResourceworks in-process), which is why this wasn't caught earlier —swamp data get,swamp data list, and CEL expressions likedata.latest()all resolve from the filesystem and worked fine.Fix: Destructure
getHandlesfrom both writer factories, then use the combined writer handles as fallback whenresult.dataHandlesis empty. Built-in models that return explicitdataHandlesare unaffected — the fallback only triggers when the method returns no handles.src/domain/drivers/raw_execution_driver.ts— wire upgetHandlesfrom both factories, use as fallbacksrc/domain/drivers/raw_execution_driver_test.ts— 3 new tests: writer handles collected when method returns none, explicit handles take precedence, empty when no writesTest Plan
RawExecutionDrivercovering the fix and backward compatibilitydeno check,deno lint,deno fmtall clean🤖 Generated with Claude Code