Kotlin port: var-kotlin authoring facade + var-kotest adapter over the Java engine - #7
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
…ations Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
The plan's single-class overload ladder was ambiguous for parameterless lambdas (K2: 'Overload resolution ambiguity' between the arity-0 and arity-1 sensor/context/action overloads), and a strictly arity-matched SAM registration would break the approved zero-parameter sensor at execution time (Execute.invokeHandler matches by exact parameter count). Resolved with two internal changes that keep the approved author API verbatim: - zero-parameter overloads are StepsScope members, capturing arities are top-level extensions — members win resolution for parameterless lambdas, extensions catch parameter-declaring ones - handlers register through arity-tolerant ContextAdapter/SensorAdapter shims exposing one apply overload per call shape, dropping surplus captured arguments (TS-facade semantics); declaring more parameters than the step supplies raises an authoring error Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
… package Closes the review finding that DefineStateTest (same package as the DSL) cannot catch a missing-import regression for the extension-function overloads: real .steps.kt files live in their own packages and need explicit imports of context/action/sensor alongside defineState. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
… duplicate per-file defineState Generalize StepLoader to resolve classes via reflection to step-definition load units: either (a) classes implementing StepDefinitions (instantiated, original path), or (b) classes exposing public static no-arg methods returning StepDefinitions (each invoked; name-sorted for determinism). This is the plain-Java shape of what a Kotlin top-level `val steps = defineState(...)` compiles to (a file-facade class with a static getter), but the check is Kotlin-agnostic. Add duplicate-file detection: when two load units' steps report the same expressionSourceFile, reject with "one defineState per step-definition file" error, closing the latent silent-overwrite risk (Tasks 6–9 rely on static factories). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
…oader Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
…t fixtures Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
VarSpec extends Kotest's FunSpec: discovers .md specs via var-runner's Discovery, loads steps via StepLoader, plans via Run.planSpec, and registers one Kotest container per spec file with one test per planned example. Delegates discovery/loading/planning/failure-rendering wholesale to var-runner; no pipeline logic in the adapter itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
Also opts in to @KotestInternal on the registration guard's Spec.tests() call so the build stays warning-free (Task 9 review minor). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
Final whole-branch review findings: - VarSpecFailureTest drives a deliberately failing spec through the real Kotest engine via EngineTestKit and asserts the example fails with an AssertionError carrying Render.renderFailure's span-anchored text (note: Kotest reports the per-file container as a TEST-type descriptor that succeeds independently of its failing child) - spec doc: correct fixture package (varkt), the sourceDirs-not-build-helper conformance wiring, the per-module kotlin-maven-plugin config, and the false package-scanning claim (StepLoader resolves FQCNs individually) - VarSpec javadoc: diagnostics defer matches var-pytest only (var-junit surfaces diagnostics via ReportEntry since b7b093b) - VarSpecSmokeTest: document Surefire's 'Tests run: 0' Kotest counting quirk - DefineState: drop HandlerAdapter's unused type parameter Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Kotlin port — unlike TypeScript→Python→Java, this does not re-port the pipeline: it layers an idiomatic Kotlin authoring API on the existing, conformance-green Java engine (the design decision the
adding-a-language-portskill required writing down; see the spec).Authoring looks like this — one top-level
valper.steps.ktfile, no class, state as the handler receiver:What's in the box
java/var-kotlin— thecom.oselvar.varktfacade:defineStatereturns an inert, replayableStepDefinitions(no static accumulator — registration only happens when the runner replays the block against a freshRegistrar);StateBoxbridges bare data classes into the engine'sC extends Statebound;suspendhandlers from day one viarunBlocking; customparameterTypes.java/var-kotest—VarSpec : FunSpec(): subclass it, point the shared three config keys at your specs/steps, one Kotest test per planned example; failure rendering delegated toRender.renderFailure(span-anchored).var-junitworks unmodified — the existing JUnit Platform engine drives Kotlin-authored steps end to end (proven byEngineTestKitsmoke tests).@RegistrarGluesoStackWalkersource locations skip DSL glue frames and point at the author's.steps.kt;StepLoadernow loads public static no-arg factory methods returningStepDefinitions(what a top-levelvalcompiles to) and rejects twodefineStateregistrations per source file.*.steps.ktfixtures in the shared corpus, registry stage gated byte-for-byte against the committed goldens (goldens untouched); stem-compatible file names (numerals.steps.kt) need zero changes toConformance.fileStem.Design notes (recorded in the spec's Risks-RESOLVED section)
sensor("…") { cukes }with same-scope arity overloads). Resolved with a member/extension split (members win resolution for parameterless lambdas) plus arity-tolerant handler adapters (surplus captured args dropped, TS semantics) — the interview-approved API compiles and runs verbatim. Consequence: authors importcontext/action/sensoralongsidedefineState(IDE auto-import).@file:RegistrarGlueon the DSL file annotates the file-facade class so extension-registered steps still attribute to the author's file.Testing
Full reactor (
mvn -f java/pom.xml clean test): 351 tests, 0 failures across all six modules, including 12/12 registry conformance, both engine smokes (JUnit + Kotest), and the failure-rendering path through the real Kotest engine.Docs: design spec (
docs/superpowers/specs/2026-07-01-kotlin-facade-design.md, with resolved risks) + task plan. Known follow-ups (from the final review, deliberately post-merge): Kotest diagnostics parity with var-junit's ReportEntry, kotlin-maven-pluginpluginManagement+kotlin-reflect/coroutines pins, sharedrelPosixhelper, CLAUDE.md repo-layout addition ofjava/.🤖 Generated with Claude Code
https://claude.ai/code/session_017h1WEs7ReorF43DQsu4u4K