Skip to content

Drop the polyfill for native workspace APIs - #16

Merged
eunomie merged 9 commits into
dagger:mainfrom
eunomie:java-sdk-pr-12-rework-lead-91d8f8fe
Aug 20, 2026
Merged

Drop the polyfill for native workspace APIs#16
eunomie merged 9 commits into
dagger:mainfrom
eunomie:java-sdk-pr-12-rework-lead-91d8f8fe

Conversation

@eunomie

@eunomie eunomie commented Aug 20, 2026

Copy link
Copy Markdown
Member

Reworks #12.

The Java SDK depended on dagger/polyfill for two things: selecting the modules it manages, and diffing before/after workspace state into a generated-files changeset. Both are now native in the engine (dagger/dagger#13854, #13855), so the dependency goes.

Module selection. currentModule.asSDK(workspace:).modules returns this SDK's registered modules, workspace-root-relative, already narrowed by the engine to the client's cwd — everything at or below it, plus the nearest enclosing module when the cwd is not itself one. That is exactly what the polyfill's findConfigDirs walk intersected with the workspace's managed-module list produced, so the walk, the intersection, and the cwd-to-root path mapping all go.

Changesets. #13855 set changesetCwdCutover = "v1.0.0-beta.10": past that engine version the engine measures a Workspace.changes result from the workspace cwd itself, and fails loudly on a change that falls outside it. generateModule used to re-root its own result to compensate and raise for a module found above the cwd; declaring the version hands both back to the engine. What is left is the shape #13855 was designed for — keep the baseline you already hold, derive, diff:

let staged = wsWithDeps
  .withNewDirectory(workspaceRef(joinPath(rootPath, "sdk")), vendored)
  .withNewDirectory(workspaceRef(joinPath(rootPath, "src/generated/java")), entrypoint)
…
after.changes(wsWithDeps)

The baseline is the dependency-staged workspace, not the one handed in: the dependencies' generated code belongs to their own SDKs and must stay out of this changeset — the job the filtered before-directory used to do.

Module sources now resolve through Workspace.moduleSource and ModuleSource.generateLocalDependencies, which reach the requester's host session the way the polyfill's nested client did. The guard around the dependency staging goes with it: it existed because the polyfill call failed outright on a synthetic workspace, and it short-circuited nothing the engine does not already short-circuit.

Also in here, needed to make the above work:

  • The e2e fixture's as-sdk paths were resolved one directory too deep after dagger/dagger@b79115ac5 made them relative to the config that declares them. This was already broken on main.
  • Two codegen fixes, both convergent with dagger/dagger's own copy of this generator: escaping the javadoc comment terminator (a glob example such as **/target/** in a schema description ended the comment early and produced uncompilable Java), and modelling an id-bearing GraphQL interface as IDAble<ID> so an interface-typed argument serializes by ID.
  • sdk-sdk moves to 00bb067, which picks up dagger/sdk-sdk#20 — the harness now runs its contract checks on the configured CLI release. Before it, a CLI older than beta.10 silently skipped every function taking a Workspace! argument, which is both initModule and the default Java template's constructor.

dagger check: 31/31.

The e2e fixtures declare their managed modules in
.dagger/modules/e2e/fixtures/dagger.toml, and dagger/dagger b79115ac5 gave
as-sdk paths the same resolver every other path in a dagger.toml already had:
relative to the directory holding that config, with a leading "/" to anchor
at the workspace root. The fixture still spelled them from the workspace
root, so every entry resolved one fixture root deeper than the module it
names and the managed-module list came back empty.

Signed-off-by: Yves Brissaud <yves@dagger.io>
A schema description that shows a glob example — Workspace.findRoots documents
its exclude argument as ["**/target/**"] — carries a comment terminator, and
javapoet copies the description into the generated javadoc verbatim. The
comment ends early and the generated client no longer parses:

  Workspace.java:[1110,78] <identifier> expected

Escape it the way dagger/dagger's own copy of this codegen does.

Signed-off-by: Yves Brissaud <yves@dagger.io>
A GraphQL interface that exposes an id field is IDAble exactly like an object,
but only objects were generated as such — so an interface-typed argument (a
Node, as LLM.withTools takes) had no overload to serialize through and was
marshalled as a plain object instead of by ID.

Reuse the providesId() test ObjectVisitor already applies, matching
dagger/dagger's own copy of this codegen; in the current schema that covers
Node, Exportable and Syncer.

Signed-off-by: Yves Brissaud <yves@dagger.io>
Regenerated with `dagger generate packager`. Generation resolves the plugin
from prebuilt/m2 and never compiles the vendored sources, so the two preceding
codegen fixes only take effect once this jar carries them.

Signed-off-by: Yves Brissaud <yves@dagger.io>
currentModule.asSDK now answers the question this SDK was reconstructing by
hand: it returns the modules registered to this SDK, already narrowed to the
client's cwd — everything at or below it, plus the nearest enclosing module
when the cwd is not itself one — with workspace-root-relative paths.

That is exactly the polyfill's findConfigDirs walk intersected with the
workspace's managed-module list, so drop the walk, the intersection, and the
cwd-relative-to-root-relative mapping the walk needed.

Signed-off-by: Yves Brissaud <yves@dagger.io>
Workspace.moduleSource now resolves a module the way the polyfill's nested
client did — through the workspace's own owning client, so SDK and
user-defaults loading still reach the requester's host session — and
ModuleSource.generateLocalDependencies is native too. Call both directly.

The guard around the dependency staging goes with it. It was there because the
polyfill call needed an owning client and so failed outright on a synthetic
workspace (Directory.asWorkspace, which the e2e checks build) even for a module
with no dependencies at all; the native call recognises a value workspace and
resolves against its own contents. What is left short-circuits nothing: the
dependency list it inspected cost the same module-source resolution the staging
call does, and the engine already skips git dependencies and returns an empty
changeset when there is nothing to stage.

generateModule loses its path argument while it is being rewritten anyway. Its
only caller passed rootPath, the field on the same object, and the two spellings
had already drifted apart — the dependency staging said rootPath while every
other line said modPathArg.

Signed-off-by: Yves Brissaud <yves@dagger.io>
Nothing in this module reaches for the polyfill any more: module selection goes
through currentModule.asSDK and module sources through the workspace.

dagger.lock keeps its polyfill entry for now. That file locks the whole
workspace, and the sdk-sdk check harness installed there still resolves the
polyfill at this pin; the entry goes when that pin moves.

Signed-off-by: Yves Brissaud <yves@dagger.io>
The engine applies a generator's changeset relative to the client's cwd, so a
workspace-rooted changeset lands every path under the cwd a second time and
leaves the module ungenerated. This SDK re-rooted its own result to compensate,
and raised for a module found above the cwd, because the changesets came back
workspace-rooted.

dagger/dagger#13855 moved that into the engine: from v1.0.0-beta.10 a
Workspace.changes result is measured from the workspace's own cwd, the caller
supplies the baseline to compare against, and a change that falls outside the
cwd fails loudly instead of being dropped. Declare the version and hand the work
back — stage onto the workspace value and diff it against the baseline already
in hand.

The baseline is the dependency-staged workspace, not the one handed in: the
dependencies' generated code belongs to their own SDKs and must stay out of this
changeset, which is what the filtered before-directory used to express.

Signed-off-by: Yves Brissaud <yves@dagger.io>
Picks up dagger/sdk-sdk#20, which threads daggerCliVersion into mod-test so the
contract checks run on the configured CLI release rather than mod-test's own
default, and moves that default to 1.0.0-beta.10 — new enough to build a flag
for a Workspace argument. All four contract checks failed here without it: the
harness silently skipped initModule, which takes a Workspace, and reported the
caller's assertion message rather than the underlying failure.

Also picks up the harness's own polyfill removal.

Signed-off-by: Yves Brissaud <yves@dagger.io>
@eunomie
eunomie marked this pull request as ready for review August 20, 2026 15:51
@eunomie
eunomie merged commit 8d0abd3 into dagger:main Aug 20, 2026
32 checks passed
@eunomie
eunomie deleted the java-sdk-pr-12-rework-lead-91d8f8fe branch August 20, 2026 15:52
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