fabro/lib/crates
Scott Werner ee7453418b
Unify @file inlining under an ImportableTemplate type (prompt + goal) (#527)
## What

Introduces an `ImportableTemplate` type that unifies the "inline content
**or**
`@path` file import" concept used by node `prompt`s, the graph `goal`,
and
`output_schema`. This is the last template-side piece of the
interpolation
unification: a single named type now owns the `@`-classification and
static-reference validation that was previously hand-rolled in three
places.

This is a **behavior-preserving refactor** — no user-visible change.

## How

- New `ImportableTemplate { Inline(String), Import { path } }` in
`transforms/importable_template.rs`, with `parse` (classifies a value —
a
leading `@` marks a file import), `import_path`, and `validate` (rejects
template syntax in an import path). Callers of templated fields classify
the
  **already-rendered** string, because a leading `@` can be produced by
  rendering (e.g. `{{ inputs.prompt_file }}` → `@prompts/work.md`).
- `prompt` + `goal`: render the inline value, then — if it's an `@file`
import —
load and render the file contents via the type. The missing-file →
literal
  passthrough is preserved.
- `output_schema`: shares the same classification but is loaded
**verbatim** (it
is intentionally not a template), keeping its hard-error-on-missing-file
  behavior.
- Deletes the dead `resolve_file_ref` helper (no non-test callers) and
inlines
  the trivial `render_file_contents` wrapper.
- Migrates the `FilesystemFileResolver` coverage (tilde, `..`,
fallback-dir
  precedence, missing file) — which previously only existed through
  `resolve_file_ref`'s tests — onto direct `file_resolver` tests.

`TemplateTransform` and the import transform are untouched, so
goal-before-
prompts ordering and the goal-self-reference guard are preserved
exactly.

## Scope

Covers the DOT node `prompt` + graph `goal` `@file` path. The
settings-layer
`run.goal` resolution is intentionally left as-is — it uses a different
model
(interpolates env into the file path and does not render file contents),
so
folding it in would be a semantic change, not a refactor. That
convergence can
be a deliberate follow-up.

## Testing

- `cargo nextest run -p fabro-workflow` — 1182 passed (31
e2e/credentialed
skipped). New unit tests on the type (classification, validation) and
the
  migrated `FilesystemFileResolver` tests.
- Regression net kept green: file-inlining (prompt/goal, output_schema
  verbatim/error/routing, `{% include %}` rooting, fallback dir), the
`TemplateTransform` goal/self-reference/ordering tests, and the
cross-pass
  `reports_goal_self_reference_once_across_passes`.
- `cargo +nightly fmt --check --all` and nightly
  `clippy --workspace --all-targets -- -D warnings` clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 15:51:46 -04:00
..
build-support fix(build): refresh embedded git sha on branch commits 2026-05-09 14:10:04 -04:00
fabro-acp fix(workflow): capture configured artifacts once (#337) 2026-05-21 10:52:22 -04:00
fabro-agent fix(mcp): honor inline enabled=false and per-server tool_timeout (#520) 2026-06-24 16:17:27 -04:00
fabro-api feat(api): add /api/v1/mcp-servers OpenAPI endpoints (#522) 2026-06-25 15:50:13 -04:00
fabro-auth feat(llm): Amazon Bedrock provider — Converse codec, SigV4 + API-key auth (#459) 2026-06-16 11:46:49 -04:00
fabro-automation refactor(server): extract reusable git-checkout/materialization core (#523) 2026-06-24 16:17:44 -04:00
fabro-checkpoint Demote non-interpolating config fields to plain String (#492) 2026-06-16 13:16:31 -04:00
fabro-cli Unify @file inlining under an ImportableTemplate type (prompt + goal) (#527) 2026-06-25 15:51:46 -04:00
fabro-client Add fabro variable CLI namespace for server-managed variables (#434) 2026-05-27 13:57:25 -04:00
fabro-config Unify @file inlining under an ImportableTemplate type (prompt + goal) (#527) 2026-06-25 15:51:46 -04:00
fabro-core Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-dev feat(llm): Amazon Bedrock provider — Converse codec, SigV4 + API-key auth (#459) 2026-06-16 11:46:49 -04:00
fabro-dump feat(web): add server-managed Environments CRUD settings UI (#462) 2026-06-13 08:44:38 -04:00
fabro-environment feat(workflow): support overriding cwd for local sandbox provider (#467) 2026-06-14 12:32:32 -04:00
fabro-github fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-graphviz fix(graphviz): render comments with template braces (#509) 2026-06-15 15:15:01 -04:00
fabro-hooks Add event-sourced todo tools for OpenAI and Anthropic profiles (#353) 2026-05-22 13:44:42 -04:00
fabro-http refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-install feat(web): add server-managed Environments CRUD settings UI (#462) 2026-06-13 08:44:38 -04:00
fabro-interview Replace stdin JSONL control pipe with WebSocket worker control bus (#440) 2026-05-27 20:24:25 -04:00
fabro-llm feat(llm): Amazon Bedrock provider — Converse codec, SigV4 + API-key auth (#459) 2026-06-16 11:46:49 -04:00
fabro-macros refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-manifest Demote non-interpolating config fields to plain String (#492) 2026-06-16 13:16:31 -04:00
fabro-mcp fix(mcp): honor inline enabled=false and per-server tool_timeout (#520) 2026-06-24 16:17:27 -04:00
fabro-mcp-server feat: Add approve/deny run controls to MCP and CLI (#400) 2026-05-25 15:49:57 -04:00
fabro-mcp-store feat(mcp): add server-side MCP server store (fabro-mcp-store) (#521) 2026-06-25 15:50:02 -04:00
fabro-model feat(llm): Amazon Bedrock provider — Converse codec, SigV4 + API-key auth (#459) 2026-06-16 11:46:49 -04:00
fabro-oauth Replace bare unwrap() with documented expect() across production runtim… (#415) 2026-05-26 17:46:39 -04:00
fabro-options-metadata refactor(dev): simplify generated docs tooling 2026-04-24 18:41:00 -04:00
fabro-proc refactor(static): centralize env var names 2026-04-24 12:29:51 -04:00
fabro-redact feat(llm): Amazon Bedrock provider — Converse codec, SigV4 + API-key auth (#459) 2026-06-16 11:46:49 -04:00
fabro-sandbox feat(workflow): support overriding cwd for local sandbox provider (#467) 2026-06-14 12:32:32 -04:00
fabro-server Unify @file inlining under an ImportableTemplate type (prompt + goal) (#527) 2026-06-25 15:51:46 -04:00
fabro-slack Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-spa feat(dev): gitignore embedded spa assets 2026-04-26 21:31:11 -04:00
fabro-static feat(llm): Amazon Bedrock provider — Converse codec, SigV4 + API-key auth (#459) 2026-06-16 11:46:49 -04:00
fabro-store feat(web): add server-managed Environments CRUD settings UI (#462) 2026-06-13 08:44:38 -04:00
fabro-telemetry Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-template Interpolate run variables ({{ vars.* }}) in node prompts and goals (#524) 2026-06-24 16:18:09 -04:00
fabro-test feat(web): add server-managed Environments CRUD settings UI (#462) 2026-06-13 08:44:38 -04:00
fabro-tool feat(web): add server-managed Environments CRUD settings UI (#462) 2026-06-13 08:44:38 -04:00
fabro-tracker fix(github): refresh installation tokens during workflows 2026-05-06 07:15:18 -04:00
fabro-types Unify @file inlining under an ImportableTemplate type (prompt + goal) (#527) 2026-06-25 15:51:46 -04:00
fabro-util Replace vague expect/panic messages with invariant-explaining messages (#422) 2026-05-27 10:38:20 -04:00
fabro-validate fix(graph): support dotted Fabro graph attributes (#324) 2026-05-20 09:31:08 -04:00
fabro-variable Interpolate run variables ({{ vars.* }}) in node prompts and goals (#524) 2026-06-24 16:18:09 -04:00
fabro-vault feat(server): add variables API (#430) 2026-05-27 11:46:36 -04:00
fabro-workflow Unify @file inlining under an ImportableTemplate type (prompt + goal) (#527) 2026-06-25 15:51:46 -04:00