Skip to content

feat(provider-fn): enforce declarative signatures on provider functions#57

Open
raphaelvigee wants to merge 1 commit into
masterfrom
feat-provider-fn-signatures
Open

feat(provider-fn): enforce declarative signatures on provider functions#57
raphaelvigee wants to merge 1 commit into
masterfrom
feat-provider-fn-signatures

Conversation

@raphaelvigee

Copy link
Copy Markdown
Member

Context

Provider-exposed functions (heph.<provider>.<fn>, added in #656d9ab) advertised only a name + handler. Args and the return were untyped htvalue::Value, the Starlark bridge installed every function with param_spec: for_arguments() / return_type: Ty::any(), and each handler hand-rolled its own validation. A typo, wrong type, or bad arity slipped past the engine.

Change

Add a declarative signature to ProviderFunctionDef — typed positional + named params (required/optional + default) and a typed return — and enforce it (hard-fail).

  • src/htvalue/signature.rs (new): ParamType (reuses htvalue::Value kinds — String/Bool/Int/Uint/Float/Null/List/Map), Param, FnSignature with validate_args/validate_return (errors name the function + offending param) and render().
  • Registry carries the signature (RegisteredFn). The bridge validates args and the return value around every call — the canonical guard, and the only one that checks the return at runtime.
  • build_globals drives Starlark's native param_spec/return_type from the signature, so BUILD-time also gets arity/type errors + typing/docs. Both layers enforce.
  • pluginfs glob/join/dir/base declare signatures; join now takes one list[string] (was variadic); redundant hand-rolled checks dropped.
  • inspect functions prints the rendered signature, e.g. heph.fs.glob(pattern: string) -> list[string].

Scope

Provider functions only — not target, not driver config.

Test plan

  • cargo build + cargo clippy --all-targets -- -D warnings clean; cargo fmt applied.
  • Full lib suite: 943 passed, 0 failed.
  • New: 9 validator unit tests (htvalue/signature.rs) + 6 e2e BUILD-eval tests (missing required, wrong type, too-many-positional, unknown kwarg, join requires-list, join accepts-list).

🤖 Generated with Claude Code

Provider-exposed functions (heph.<provider>.<fn>) advertised only a name +
handler; args and return were untyped htvalue::Value, the Starlark bridge
installed them with for_arguments()/Ty::any(), and each handler hand-rolled
its own validation.

Add a declarative signature (typed positional + named params with
required/optional/default, typed return) to ProviderFunctionDef and enforce it:

- htvalue/signature.rs: ParamType (reuses htvalue::Value kinds), Param,
  FnSignature with validate_args/validate_return (hard-fail, naming the
  function + offending param) and render().
- Registry carries the signature (RegisteredFn). The bridge validates args
  and the return value around every call — the canonical guard, and the only
  one that checks the return at runtime.
- build_globals drives Starlark's native param_spec/return_type from the
  signature, so BUILD-time also gets arity/type errors and typing/docs.
- pluginfs glob/join/dir/base declare signatures; join now takes one
  list[string] (was variadic); redundant hand-rolled checks dropped.
- inspect functions prints the rendered signature
  (e.g. heph.fs.glob(pattern: string) -> list[string]).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
for (provider, func) in engine.provider_functions() {
println!("heph.{provider}.{func}");
for (provider, _func, rendered) in engine.provider_functions() {
println!("heph.{provider}.{rendered}");

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove heph. prefix

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant