make slog.Handler optional in engine subpackages; drop dead engines.NewEvaluator dispatcher#105
Conversation
…ewEvaluator dispatcher (#85) Each engine subpackage now exposes a single FromXLoader(ldr, opts...) constructor with engine-scoped options: - WithLogHandler / WithStaticData / WithDataProvider on all three - WithEntryPoint on engines/extism (required) The four FromXLoaderWithData/NewEvaluator variants per engine fold into the new options form. polyscript.New[E] and deprecated.go translate to the new shape internally; the deprecated public surface is unchanged. Default-handler logic moves to a single source of truth: internal/helpers.SetupLogger now inherits from slog.Default() when given nil. The redundant stderr fallback in each compiler's applyDefaults is removed. engines/new.go's NewEvaluator/NewCompiler dispatchers were dead public API (no callers outside the file's own test); both they and the generator templates that produce them are deleted. Closes #85
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
…ns, gofmt integration_test.go Addresses six golangci-lint findings on PR #105: - usetesting: replace context.Background() with t.Context() in the new RunsEndToEnd tests under engines/{risor,starlark,extism}/new_test.go - testifylint require-error: switch assert.ErrorIs to require.ErrorIs in TestFromExtismLoader_RequiresEntryPoint and TestFromExtismLoader_EmptyEntryPointStillRejected - gofmt: re-align over-indented option args in integration_test.go Drops the now-unused context import in the three new_test.go files.
Sonar S3776: New[E]'s 20-rated complexity exceeded the 15 budget. Moves the per-engine option-building blocks into newRisor/newStarlark/newExtism helpers, leaving New[E] as a thin dispatcher. No behavior change.
There was a problem hiding this comment.
Pull request overview
This PR completes the migration to an options-driven construction API for the per-engine subpackages (risor/starlark/extism), making slog.Handler optional (nil-tolerant) and removing redundant constructors and the unused engines.NewEvaluator/engines.NewCompiler dispatch surface. It also centralizes default logging fallback behavior in internal/helpers.SetupLogger and updates docs/tests accordingly.
Changes:
- Replace per-engine positional constructors with
FromXxxLoader(ldr, opts...)plusWithLogHandler/WithStaticData/WithDataProvider(and ExtismWithEntryPoint) options. - Centralize nil-handler fallback to inherit from
slog.Default()ininternal/helpers.SetupLogger; remove compiler stderr defaults. - Remove generated
engines/new.godispatcher and its generator templates; update README and tests to match the new APIs.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds “Direct engine subpackage usage” docs showing the new per-engine options API. |
| polyscript.go | Updates polyscript.New[E] to call per-engine FromXxxLoader with options and omit handler when nil. |
| platform/script/executableUnit.go | Documents and relies on nil-handler support via helpers.SetupLogger. |
| platform/script/executableUnit_test.go | Adds regression coverage ensuring NewExecutableUnit works with a nil handler. |
| internal/helpers/logger.go | Changes default logging fallback to inherit from slog.Default().Handler() when handler is nil. |
| internal/helpers/logger_test.go | Adds tests covering default inheritance and grouping behavior in SetupLogger. |
| engines/types/gen/typeGen.go | Stops generating engines/new.go and engines/new_test.go. |
| engines/types/gen/templates/new.go.tmpl | Deleted: generator template for the engines dispatcher. |
| engines/types/gen/templates/new_test.go.tmpl | Deleted: generator template for the engines dispatcher tests. |
| engines/starlark/options.go | New: defines the engine-scoped options for FromStarlarkLoader. |
| engines/starlark/new.go | Replaces multiple constructors with a single options-driven FromStarlarkLoader. |
| engines/starlark/new_test.go | Rewrites tests to cover nil/no handler, options precedence, and end-to-end evaluation. |
| engines/starlark/doc.go | New: package docs for direct engine-level usage and options. |
| engines/starlark/compiler/options.go | Removes stderr default handler; defers nil-handler behavior to helpers.SetupLogger. |
| engines/starlark/compiler/options_test.go | Updates expectations around logging defaults/validation after deferring to SetupLogger. |
| engines/risor/options.go | New: defines the engine-scoped options for FromRisorLoader. |
| engines/risor/new.go | Replaces multiple constructors with a single options-driven FromRisorLoader. |
| engines/risor/new_test.go | Rewrites tests to cover nil/no handler, options precedence, and end-to-end evaluation. |
| engines/risor/doc.go | New: package docs for direct engine-level usage and options. |
| engines/risor/compiler/options.go | Removes stderr default handler; defers nil-handler behavior to helpers.SetupLogger. |
| engines/risor/compiler/options_test.go | Updates expectations around logging defaults/validation after deferring to SetupLogger. |
| engines/new.go | Deleted: public dispatcher API that had no external callers. |
| engines/new_test.go | Deleted: tests for the removed engines dispatcher API. |
| engines/integration_test.go | Updates integration tests to use the new per-engine options constructors. |
| engines/extism/options.go | New: defines the engine-scoped options for FromExtismLoader, including WithEntryPoint. |
| engines/extism/new.go | Replaces multiple constructors with a single options-driven FromExtismLoader and adds ErrEntryPointRequired. |
| engines/extism/new_test.go | Rewrites tests to cover entry point validation, nil/no handler, options precedence, and end-to-end evaluation. |
| engines/extism/doc.go | New: package docs for direct engine-level usage and options (including required entry point). |
| engines/extism/compiler/options.go | Removes stderr default handler; defers nil-handler behavior to helpers.SetupLogger. |
| engines/extism/compiler/options_test.go | Updates expectations around logging defaults/validation after deferring to SetupLogger. |
| deprecated.go | Keeps deprecated top-level constructors but translates them into the new per-engine options form. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Address Copilot review feedback on PR #105: - engines/{risor,starlark,extism}/new.go: WithLogHandler on the loader was reaching the evaluator and ExecutableUnit but not the compiler, so compiler-level logs still went through slog.Default(). Now the compiler is constructed with compiler.WithLogHandler(cfg.handler) when non-nil. Renamed the local 'compiler' variable to 'comp' to unshadow the imported compiler package. - internal/helpers/logger.go: SetupLogger doc previously implied engineName was always added as a slog group. Clarify that engineName is only applied when handler is nil (the implicit-default branch); when an explicit handler is passed, the caller is presumed to have configured grouping the way they want. Switched the doc reference from [slog.Default] to slog.Default().Handler(). - engines/{risor,starlark,extism}/new_test.go and internal/helpers/logger_test.go: add a comment on each SetDefault- using test marking it non-parallel-safe (per-package mutation must be serialized; cross-package isolation comes from one process per package under `go test ./...`).
…e, clarify logger doc - polyscript.New[Extism] now wraps extism.ErrEntryPointRequired so callers can detect the condition with errors.Is across both APIs - README Extism example is self-contained: constructs a WASM-appropriate loader (loader.NewFromBytes) with required imports - SetupLogger doc references the actual <engineName>.<...> prefix instead of a literal "engine.<...>"
|
PR #105 (issue #85) made SetupLogger inherit from slog.Default() when given nil, but three constructors still wrote a fresh TextHandler to os.Stdout in that case: - engines/extism/evaluator/response.go newEvalResult - engines/risor/evaluator/response.go newEvalResult - engines/starlark/evaluator/response.go newEvalResult That's the exact "library writes to stdout when nil-handler" pattern issue #99 was filed against. Replace each with a single helpers.SetupLogger(handler, "<engine>", "execResult") call so nil now inherits from slog.Default() like the rest of the package, and the "Handler is nil, using the default logger configuration" warning goes away. The (engine, execResult) group structure is preserved. Also drops three stale TODOs: - platform/data/addDataToContext.go: "// TODO: remove or use logger more effectively" — the slog.Default() fallback is the right behavior post-#85; the TODO is a leftover. - engines/extism/compiler/compiler.go: "TODO: error paths hard to test" — converted to issue #108 with concrete branch list and a proposed adapter-mock approach. - engines/extism/evaluator/evaluator.go: same TODO — converted to issue #109 with the equivalent treatment for Eval/exec/execHelper. Coverage on extism compiler/evaluator is ~93%; the remaining branches need adapter-level mocking, tracked under #108/#109. Closes #99 Co-authored-by: Claude <noreply@anthropic.com>
* docs: add LOGGING.md describing the logging philosophy Captures the design decisions arrived at across PRs #105, #110, #113, and #114 (issues #85, #99, #111, #112) — the four-PR convergence on: - Logging is opt-in; no constructor demands a slog.Handler. - nil handler means "inherit from slog.Default()" at every layer. - Exactly one fallback path: helpers.SetupLogger. - Functional options are silent on nil (Go idiom). - Group naming follows (engine, struct) shape. Includes a prior-art section showing how each choice tracks stdlib slog, slog.DiscardHandler, OpenTelemetry otelslog, go-logr/logr, the Cheney/Pike functional-options lineage, and database/sql. Also covers the explicitly-rejected alternatives (stdout fallback, nil-warning at construction, panic on nil at option layer, mandatory handler argument, library-defined logger interface) with the failure mode for each. Architectural map shows every nil-handler path funnels through helpers.SetupLogger; history table maps the four issues to the four PRs that shipped them. This is a contributor-facing engineering document. The README's "Capturing diagnostic logs" section is unchanged for now and remains the user-facing entry point; can be linked in a follow-up if desired. * docs(LOGGING): correct three Copilot review findings Three substantive corrections from PR #115 review (Copilot): 1. Principle 1 over-claimed "true no-op on nil" for all four option layers. Only the compiler-level WithLogHandler/WithLogger (relaxed in #111 / PR #113) skip both the set and the clear-of-the-other- field. The top-level and per-engine WithLogHandler do plain field assignment — they accept nil but don't preserve a prior non-nil value across the same option list. Doc now distinguishes the two layers and explains why the distinction is benign for the common single-call case. 2. Principle 2 said records carry the `<engine>.<struct>` prefix "regardless of whether the host configured a handler." That's not true: helpers.SetupLogger only adds the engineName group when the handler is nil. With a host-supplied handler the prefix is just `<struct>`. Doc now describes the asymmetry and explains why it's deliberate (library-owned sink vs. host-owned sink). 3. Principle 5 used `engine=extism` / `script=ExecutableUnit` filter examples that conflate slog groups with key/value attributes. Rephrased to describe slog.Handler.WithGroup behavior accurately (group qualifier on attribute keys; JSON nesting; text prefix) and to condition the `<engine>` prefix on the nil-handler case. The fourth Copilot comment (line 233 — claimed extra leading `|` in the markdown table) was a false positive; the table source has the correct single leading pipe per row and renders as three columns on GitHub. Skipped. --------- Co-authored-by: Claude <noreply@anthropic.com>
* docs: add CHANGELOG.md (Keep a Changelog 1.1.0) Closes #102 Repo had no CHANGELOG.md; users had to read GitHub release notes to find what changed between versions. With v1 ahead and a queue of breaking changes (#86, #87, #88, #89, #90, #91, #104), having a CHANGELOG before landing those gives downstream code reviewers and IDEs visibility into what's coming. Format follows Keep a Changelog 1.1.0 with the standard six headings (Added / Changed / Deprecated / Removed / Fixed / Security). [Unreleased] section captures the run of merged-but-not-released PRs since v0.7.0: - #103 polyscript.New[E] generic constructor (deprecates 12 FromXxx) - #105 slog.Handler optional in engine subpackages - #106 RequestToMap mutation fix - #107 HTTP loader MaxBodySize cap - #110 unify nil-handler on slog.Default(); drop stdout fallbacks - #113 WithLogHandler(nil)/WithLogger(nil) → no-op - #114 drop redundant nil-guards; tighten WithLogHandler doc - #115 docs/LOGGING.md - #117 fix bare top-level json.Number leak - #118 WithGlobals additive; drop dead URL check - #119 extism Eval test coverage Backfilled the three releases the issue called out (v0.5.0, v0.6.0, v0.7.0) from existing GitHub release notes, sorted into Keep a Changelog categories. Earlier releases (v0.0.x through v0.4.0) intentionally not backfilled per the issue scope; can be added in a follow-up if desired. Out of scope: the optional CI gate that fails PRs not touching CHANGELOG.md. Adds noise to small bug PRs and wants opt-out-label infrastructure to support it; better as a separate issue. * docs(CHANGELOG): clarify deprecated FromXxx still take positional handler Copilot review noted that "no constructor demands a handler" is misleading because the deprecated FromXxx constructors still take a positional `logHandler slog.Handler` argument (even though nil is accepted). Reword to distinguish the new generic constructor (no handler arg) from the deprecated ones (still take it, but nil is OK). --------- Co-authored-by: Claude <noreply@anthropic.com>



Summary
Closes #85.
polyscript.New[E](shipped in PR #103) already treatsslog.Handleras optional viaWithLogHandler[E]. This PR finishes the job for the per-engine subpackages, which still required handler as a positional argument and duplicatedFrom*Loader/From*LoaderWithData/NewEvaluatorconstructors.Per-engine subpackage shape
Each of
engines/risor,engines/starlark,engines/extismnow exposes a single options-driven entry point:Each subpackage has the same options:
WithLogHandler(slog.Handler)— nil-tolerant; defaults toslog.Default()WithStaticData(map[string]any)— composes aStaticProvider + ContextProviderWithDataProvider(data.Provider)— bypasses composition; takes precedence overWithStaticDataWithEntryPoint(string)— Extism only; required (returnsErrEntryPointRequiredif missing)The 6 redundant constructors (
From*LoaderWithData× 3,NewEvaluator× 3) are removed.Single source of truth for default handler
internal/helpers.SetupLoggernow inherits fromslog.Default()when handler is nil. The redundant stderr fallback in each compiler'sapplyDefaultsis removed, so there's one fallback site instead of four.engines.NewEvaluator/engines.NewCompilerremovedThese public dispatchers in
engines/new.gohad zero callers outside their own test file —polyscript.New[E]supersedes them. Deleted along with their generator templates andtypeGen.goentries.deprecated.gounchanged externallyThe 12 deprecated top-level constructors keep their existing positional
(handler, ...)signatures; their bodies translate internally into the new options form. A separate v1 issue (#104) tracks deletion.Files
engines/{risor,starlark,extism}/options.go+doc.go,internal/helpers/logger_test.goengines/new.go,engines/new_test.go, two.tmplfilesTest plan
go test -race -count=1 ./...— all greengo vet ./...— cleannew_test.gorewritten with no-handler / nil-handler / DataProvider / EntryPoint coverageinternal/helpers/logger_test.gocovers nil-handler default-inheritance, custom handler honored, group prefix behaviorplatform/script/executableUnit_test.goadds a nil-handler regression testdeprecated_test.gounchanged — locks in that the public deprecated surface still workshttps://claude.ai/code/session_01C61VEAmjxSnX5Xhbab8NvL
Generated by Claude Code