Repository navigation
devlore-test writes the receipt after deleting the workspace it reads from #720
Description
Feature: #534 — Engine and combinator coverage
Charter: docs/plans/function-resource-receipts.md
Two findings, filed together because the second is why the first survived.
1. Any graph carrying a Starlark lambda fails to write its receipt
Measured on feature/docker.devlore-package:
| Fixture | Lambdas in graph | Expectations | Exit |
|---|---|---|---|
test_compensation.star |
none | pass | 0 |
test_choose_then_action.star |
none | pass | 0 |
test_choose_exists.star |
one, default=lambda: |
pass | 1 |
test_choose_lambdas.star |
many | pass | 1 |
Error: writing receipt: op.Graph: pack tag:devlore.noblefactor.com,2026-01-01:sha256:<hash>
#…/pkg/op/provider/function.Resource: function.Resource: pack …:
mmap <workspace>/.devlore/function/resource/sha256/<xx>/<hash>: no such file or directory
Expectations pass in every case. The graph plans, executes, and satisfies its assertions; only the
receipt fails, afterwards. Routing the receipt to a real path rather than /dev/null changes
nothing.
Cause — confirmed
cmd/devlore-test/devloretest/commands.go:
result, err := runner.Start(cmd.Context()) // line 153
...
writeReceipt(outputs.entries["receipt"], receiptFmt, runner.Graph()) // line 166Runner.Start opens its workspace with fsroot.OpenScratch("devlore-test-*") under
defer iox.Close(&err, workspace), and says so in its own comment: "a scratch root, so the tree is
removed by the same Close that releases it."
The workspace — including .devlore/function/resource/sha256/… — is deleted when Start returns.
The receipt is written afterwards, and packing the graph then reads a function pack off a path that
no longer exists.
Graphs without lambdas are unaffected because nothing in them needs a disk read at pack time. A
function.Resource is deliberately metadata-only — newFromURI documents that "No content is
archived — the on-disk pack is the source of truth, rehydrated lazily." The pack is written
correctly at plan time (pkg/op/provider/function/resource.go:396-410). Nothing about archiving is
broken; only the read outlives the tree it reads from.
Production is not affected. lore and writ run against durable roots, not OpenScratch.
2. One fixture is exercised through the CLI
cmd/devlore-test/cli_test.go drives exactly one script — test_hello.star — and contains zero
references to choose. The other 103 fixtures under cmd/devlore-test/devloretest/data/ run
in-process, where receipts are not written.
The suite is therefore green while the receipt is unwritable. Same failure shape as a CI job that
passes continuously while its generator emits a near-constant artifact: a success signal that does
not cover what it appears to certify.
Candidate fixes
- Write the receipt inside
Start, before the workspace closes. - Hand the caller a closer instead of closing in
Start, moving the lifetime rather than the write. - Pack function resources eagerly at seal time so the graph document is self-contained — largest
change, and the only one that makes receipts robust to any root going away.
Exit criteria
- A fixture whose graph contains a lambda writes its receipt and exits 0.
cli_test.goexercises at least one lambda-bearing graph through the CLI, and that test is
proved to fail before it is trusted — reverting the fix must turn it red.- Ruling 8 in the docker package plan is revisited now that the cause is known to be harness-confined.
Activity