picatz / picatz/flowstate

flowfile: call: is unresolvable from every byte-based surface, and a callee may never live above the calling file

Open
#1,376 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

design dsl enhancement kind/design-record
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:

  1. 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, and embed.Compile (documented at docs/EMBEDDING.md, "compile from bytes" section). The practical edge: an agent over flow mcp can 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.
  2. A monorepo cannot share workflows across subtrees. teams/a/workflow.yaml cannot call lib/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-dir precedent 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 compile on 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 in docs/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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.