flowfile: call: is unresolvable from every byte-based surface, and a callee may never live above the calling file
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Observed behavior
call: resolves a callee relative to the calling file's directory, and refuses both an absolute path and any path that climbs above it (pkg/flowstate/v1/flowfile/call.go:134-164). Both refusals are correct for what they refuse; their composition has two consequences worth deciding deliberately rather than inheriting:
- A workflow that arrives as bytes cannot compose at all. A byte source has no directory, so every byte-based surface refuses a file containing
call:: the Compile RPC, the MCP tools (flowstate_validate,flowstate_compile,flowstate_run_local,flowstate_test), an unsaved editor buffer, andembed.Compile(documented atdocs/EMBEDDING.md, "compile from bytes" section). The practical edge: an agent overflow mcpcan author, validate, test, debug, and run any single-file workflow end to end with no server — and nothing composed. The composition primitive and the agent surface are each first-class; their intersection is empty. - A monorepo cannot share workflows across subtrees.
teams/a/workflow.yamlcannot calllib/deploy.yaml; reuse today is copying the file into every consuming subtree. This is the local, pre-remote version of the reuse question — it needs no fetching, no registry, and no new trust model, only an answer to "which roots may a resolution see".
Constraints already decided elsewhere
The resolver contract this issue asks for has to land inside decisions that are already made, cited so the design starts from them:
- Composition is vendoring, not linking: compile-time resolution, the callee embedded whole, digest-recorded; the engine never fetches and a submitted spec is hermetic forever (#172, and
docs/DSL.md's seventh round). Nothing here may add runtime resolution. - Expansion stays bounded (
MaxCallDepth, expansion-node bounds —pkg/flowstate/v1/call.go:37,pkg/flowstate/v1/structure.go). - The LSP does no I/O on the keystroke path, and a cloned repository must not be able to make an editor read outside itself (#172's LSP section; the
flow lsp --plugin-dirprecedent for person-passed capability). digest:pinning exists and is checked at compile (flowfile/parse.go,compiler.verifySourcePin); whatever a byte-surface resolution looks like, provenance has to stay checkable.
Desired outcome
A recorded resolver contract answering both halves — or refusing either half with the workaround named:
- What source identity a byte-based compile has, if any, and how a caller's callees reach it. Shapes worth writing down before choosing: a bundle form (the caller's bytes accompanied by its callees' bytes, digest-addressed — the natural fit for MCP and the Compile RPC, since the submitting side already had every file open to pin digests); a callee-by-digest lookup against explicitly provided sources; or a recorded refusal that names
flow compileon a real filesystem as the supported path. - Whether an explicitly configured root (a flag or workspace file a person passes, never repository content) may widen resolution above the calling file's directory for the monorepo case, or that stays refused with the reasoning recorded where the refusal lives.
Acceptance criteria
- An agent can validate and test a caller-plus-callee pair over MCP with no filesystem, or the refusal is a stable diagnostic naming the supported alternative rather than a resolution error.
- The monorepo
lib/question has a decided answer indocs/DSL.md, either mechanism or refusal-with-reason. - The engine's hermetic-spec property and the existing depth/expansion bounds are untouched or explicitly re-argued.
- Nothing makes resolution reachable from repository content alone (a cloned repo must not widen what an editor or validator reads).
Adjacency
#172 (the composition keystone record — the trust model this must not weaken), #1290 (the same MCP tools' input ergonomics; a bundle shape should not add a third input convention), #637 (a named type shared across files will walk whatever resolution road this decides), #641 (the expressiveness census this gap surfaced under).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with pkg/flowstate/v1/flowfile/call.go:134-164, flowfile/parse.go, compiler.verifySourcePin, and docs/DSL.md and docs/EMBEDDING.md. Trace the Compile RPC and MCP tools, then record a resolver decision covering byte-based composition and explicitly configured roots. Done means the acceptance criteria are addressed without weakening hermeticity or resolution bounds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, compilers, documentation
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100