Parse template dependencies whose paths collide with discovery roots

Batched dependency discovery pre-seeded roots into the path-keyed result
map and reused that map as the traversal-dedup set, so a loaded include
target whose path matched a root (e.g. a goal template including the
graph file that anchors an inline prompt) was recorded but never parsed,
silently accepting invalid template content that per-root discovery used
to reject. Dedup traversal on the full (path, root, content) occurrence
instead, which also stops re-parsing identical duplicate roots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Scott Werner 2026-08-17 16:36:40 -04:00
parent 408cd2f745
commit 5a5cfbdaa0

View file

@ -685,6 +685,37 @@ mod tests {
));
}
#[test]
fn validates_graph_files_included_from_goal_templates() {
// The graph file's inline prompt anchors a template root at the graph
// path; that root must not shadow the raw graph content when a goal
// template includes the graph file itself.
let error = version_with(
[
(
"workflow.fabro",
r#"digraph W {
graph [goal="@goal.md"]
step [prompt="hello", note="{% include 'missing.md' %}"]
}"#,
),
("goal.md", r#"{% include "workflow.fabro" %}"#),
],
[],
)
.unwrap_err();
assert!(matches!(
error,
WorkflowVersionError::Template { path: source_path, source }
if source_path == path("workflow.fabro")
&& matches!(
source.as_ref(),
TemplateDiscoveryError::Missing { reference, .. } if reference == "missing.md"
)
));
}
#[test]
fn accepts_root_config_and_all_dockerfile_path_sources() {
let version = version_with(