Repository navigation
artifact_exists can never pass for a dot-directory path: the worker's journaled artifacts list omits them #513
Description
Summary
An artifact_exists gate can never pass for a file under a dot-directory, because the worker's journaled artifacts list omits those paths entirely. The gate is correct by its own rules — it reads the journal — but the journal does not describe what the agent actually wrote.
.workflow-artifacts/ is the conventional artifact directory in AgentWorkforce/relay (every flow spec in that repo writes there), so in practice artifact_exists is unusable for the thing it exists to check.
Evidence
Run 01M2ZQP6P9ME3PRBWDXQA32MT3, CLI 2.0.22, macOS arm64, flows run --local-agent.
The run died at shadow-rust.gate with the file it was gating sitting on disk:
FAILED [step_failed] Step "shadow-rust.gate" (deterministic) completionReason: retries_exhausted exit=1.
$ ls -la .workflow-artifacts/migrate-native-delivery/phase-0-seam-20260920c/reviews/shadow-rust.md
-rw-r--r-- 1 khaliqgant staff 25257 Sep 20 08:57 ...
The gate was { type: 'artifact_exists', path: '.workflow-artifacts/migrate-native-delivery/phase-0-seam-20260920c/reviews/shadow-rust.md' }. shadow-rust journaled zero artifacts.
The preceding step makes the pattern unambiguous. implement-rust journaled 6,837 artifacts:
top-level prefixes: {'target': 6832, 'crates': 5}
target/ and crates/ only — and nothing under .workflow-artifacts/, despite that step provably having written evidence/mutation-proof.md there:
$ stat -f "%Sm %N" -t "%H:%M" .workflow-artifacts/.../evidence/mutation-proof.md
08:48 .workflow-artifacts/.../evidence/mutation-proof.md
So the exclusion is not .gitignore-driven: target/ is gitignored too and is included in full. The distinguishing property of the missing path is the leading dot.
Why it matters
artifact_exists is documented as the journal-honest way to check "the agent wrote X", and it is the gate an author naturally reaches for on a review or report step. Silently excluding a whole class of paths means:
- the gate fails on a file that exists, with no indication why;
- the failure is a bare
retries_exhausted exit=1(the lowered gate decides in-process, so there is no command output to inspect either); - agent-written evidence is invisible in the journal generally, not just to this gate — any consumer reading
output.artifactsto find what a step produced will miss it.
What to change
Either include dot-directories in the worker's artifact scan, or — if they are excluded deliberately, which is defensible for .git/, .relayflowd/ and friends — make the exclusion explicit and inspectable:
- document which prefixes are excluded;
- have
flows checkrefuse anartifact_existsgate whosepathfalls inside an excluded prefix, with a message naming the exclusion, rather than compiling a gate that cannot pass; - consider an opt-in (
artifacts.include) so a flow can declare its own artifact directory.
A deny-list of exactly .git/ and the runtime's own state directories would cover the real hazard without swallowing every author-chosen artifact path.
Acceptance
- Either an agent writing
.workflow-artifacts/x/y.mdhas that path in its journaledartifacts, orflows checkrefuses theartifact_existsgate naming it, before the run starts. - A test pins a dot-directory artifact path either way.
Out of scope
- Whether
artifact_existsshould consult the disk (it should not; journal-honest replay is the right design). - The unrelated
subprocess_gatestdio loss (A failing subprocess_gate journals empty stdout/stderr: the lowering uses stdio:'inherit' and the daemon's stdio is captured nowhere #511), though the two combine badly: neither gate mechanism can tell an author why it failed.
Activity
feat(skills): artifact_exists dot-directory trap, and how to watch a run
flows check knows which specs will park or fail at run time, and says…
AgentRelayBot commentedon Oct 5, 2026
Triage 2026-10-05: FIXED — commit 6990e55 makes the worker's artifact scan include dot-directories. Only entries named exactly
.git,.relayflowdandnode_modulesare skipped (packages/sdk/src/artifact-scan-policy.ts:30), so.workflow-artifacts/...now appears inoutput.artifacts. Tests are inpackages/sdk/tests/agent-artifacts.test.tsandartifact-gates.test.ts. #517 (e30226c) also hasflows checkwarn (gate_path_unscanned) when anartifact_existspath falls under one of the remaining excluded names. Both acceptance options are met.