Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate issues remain in Conda locking, dependency handling, runtime setup, and resolver integration.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds custom Conda environment.yml support with micromamba resolution, explicit locks, and provider-specific installation.
Changes:
- Extends schema and validation for Conda environments.
- Adds Conda solving and lock generation.
- Integrates Conda builds across managed providers and updates conformance checks.
File summaries
| File | Summary |
|---|---|
tests/test_environment_spec.py |
Tests publication rules. |
tests/test_environment_resolve_conda.py |
Tests Conda resolution. |
tests/test_environment_modal_builder.py |
Tests Modal Conda builds. |
tests/test_environment_managed_builders.py |
Tests managed capabilities. |
tests/test_environment_e2b_builder.py |
Tests E2B Conda builds. |
tests/test_environment_daytona_builder.py |
Tests Daytona Conda builds. |
tests/test_environment_datalayer_builder.py |
Tests Datalayer Conda builds. |
tests/test_environment_conformance.py |
Tests GPU gating. |
schemas/environment-v1alpha1.json |
Adds Conda source support. |
code_sandboxes/environments/spec.py |
Adds Conda validation and publication checks. |
code_sandboxes/environments/resolve.py |
Routes Conda resolution. |
code_sandboxes/environments/resolve_conda.py |
Implements Conda parsing, solving, and locks. |
code_sandboxes/environments/conformance.py |
Gates accelerator conformance checks. |
code_sandboxes/environments/adapters/modal.py |
Installs Conda locks on Modal. |
code_sandboxes/environments/adapters/managed.py |
Adds dependency-format capabilities. |
code_sandboxes/environments/adapters/e2b.py |
Installs Conda locks on E2B. |
code_sandboxes/environments/adapters/daytona.py |
Installs Conda locks on Daytona. |
code_sandboxes/environments/adapters/datalayer.py |
Builds Conda locks with Docker. |
Review details
Suppressed comments (5)
code_sandboxes/environments/adapters/managed.py:223
build.source == "dependencyFile"is allowed to reach capability validation before full spec validation, butspec.build.dependency_filecan still beNone. This dereference raisesAttributeErrorinstead of returning a capability report for a draft such as{"source": "dependencyFile"}; guard the missing file before readingsource_format.
source_format = spec.build.dependency_file.source_format
if source_format in self.dependency_formats:
return []
code_sandboxes/environments/resolve.py:1264
- This branch passes only the YAML content and Python version, so the conda path drops the existing package contract:
spec.packages.python.indexesand user constraints are not applied to the YAMLpip:layer, andspec.packages.system.aptis never resolved into the lock. Private pip requirements therefore fall back to the default index, while requested apt packages are silently omitted from every builder.
return resolve_conda_environment(
environment_yml=dependency_file.content,
python_version=environment.spec.language.version,
resolved_bases=resolved_bases,
credential=credential,
code_sandboxes/environments/resolve_conda.py:705
- This resolver has no apt input or output. When
resolve_environmentselects the conda path,spec.packages.system.aptis never pinned or recorded, soapt_pins_in()sees nothing and every adapter silently omits requested system packages. Resolve apt packages in the same base or explicitly reject apt packages for conda sources.
def resolve_conda_environment(
*,
environment_yml: str,
python_version: str,
resolved_bases: Mapping[str, str],
platform: str = CONDA_PLATFORM,
code_sandboxes/environments/resolve_conda.py:731
merge_conda_piponly receives the parsedpip:entries;spec.packages.python.constraintsnever reaches this path. A conda source can therefore bypass user constraints and protected-package conflicts that the normal resolver would merge or reject. Pass the Python constraints through the conda merge/resolve path.
environment = parse_conda_environment(environment_yml)
merged = merge_conda_pip(environment)
for note in merged.notes:
say(note)
rendered = rendered_environment(environment, merged, python_version=python_version)
code_sandboxes/environments/resolve_conda.py:737
CondaResolveRequesthas no index field, and the runners only setPIP_FIND_LINKS. Thuspip:dependencies inenvironment.ymlignorespec.packages.python.indexes(including private indexes) and resolve through pip's ambient/default index instead of the spec. Carry the indexes into the request and configure the pip step with them.
request = CondaResolveRequest(
environment_yml=rendered,
python_version=python_version,
platform=platform,
base_reference=solving_in,
- Files reviewed: 18/18 changed files
- Comments generated: 8
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| spec or the one pip mapping — a nested list, a bare number — is refused with | ||
| its position, because a solve is not the place to discover a malformed file. | ||
| """ | ||
| import yaml |
Comment on lines
+239
to
+241
| text = channel.strip() | ||
| if text: | ||
| channels.append(text) |
Comment on lines
+522
to
+524
| "RUN --mount=type=cache,target=/opt/conda/pkgs " | ||
| "micromamba create --yes --prefix /solve/prefix " | ||
| f"--platform {shlex.quote(request.platform)} --file environment.yml", |
Comment on lines
+678
to
+679
| for constraint in merged.constraints: | ||
| header.append(f"{PROTECTED_PIN_PREFIX}{constraint}") |
Comment on lines
+1260
to
+1266
| return resolve_conda_environment( | ||
| environment_yml=dependency_file.content, | ||
| python_version=environment.spec.language.version, | ||
| resolved_bases=resolved_bases, | ||
| credential=credential, | ||
| log=say, | ||
| resolved_at=resolved_at, |
Comment on lines
+455
to
+465
| export = subprocess.run( # noqa: S603 - the argv is built here | ||
| [self._micromamba, "env", "export", "--explicit", "--prefix", str(prefix)], | ||
| capture_output=True, | ||
| text=True, | ||
| timeout=self._timeout, | ||
| check=False, | ||
| ) | ||
| if export.returncode != 0: | ||
| for line in (export.stderr or "").splitlines(): | ||
| say(line) | ||
| raise parse_conda_failure(export.stderr or export.stdout or "") |
Comment on lines
+895
to
899
| private = [ | ||
| url | ||
| for url in environment.spec.packages.python.indexes | ||
| if not index_is_public(url) | ||
| ] |
Comment on lines
156
to
+157
| "additionalProperties": false, | ||
| "description": "A `requirements.txt`, or a `pyproject.toml` with its `uv.lock` (E3-01).\n\n``requirements`` resolves the way ``packages`` does \u2014 the protected\nconstraints merged in, the same solve. ``pyproject`` does not resolve at\nall: its own ``uv.lock`` is verified against the current\n``pyproject.toml`` and exported, never re-solved, because a lock the\nauthor already made is the whole point of bringing one.", | ||
| "description": "A `requirements.txt`, a `pyproject.toml` with its `uv.lock`, or a conda\n`environment.yml` (E3-01, E3-02).\n\n``requirements`` resolves the way ``packages`` does \u2014 the protected\nconstraints merged in, the same solve. ``pyproject`` does not resolve at\nall: its own ``uv.lock`` is verified against the current\n``pyproject.toml`` and exported, never re-solved, because a lock the\nauthor already made is the whole point of bringing one. ``conda`` resolves\nthe ``environment.yml`` in its own ``micromamba`` solve into an explicit\nlock, with the protected constraints merged over its ``pip:`` layer.", |
The pooled kernel manager moved to the public jupyter-kernels package (jupyter_kernels.pool.mapping.PooledMappingKernelManager, published as 1.2.23). PyPI serves it, so the protected pin resolves from the index and its wheel is dropped from the wheelhouse. Update the contract pin, the wheelhouse README, and the constraint/resolve tests.
…he contract's workdir
Both found by the r1 geospatial drill on 2026-09-16 — the first one
whose smoke test ran the Appendix B core tier for real against a built
artifact. Seven of nine checks passed; these are the two that did not.
- check 7 read "state survived the restart ('True')".
CodeSandboxClient.restart() was stop() + start(), which destroys and
recreates a sandbox this process owns but only drops the websocket of
one attached to somebody else's Jupyter server — the kernel process
keeps running and the reconnect lands in the same interpreter.
JupyterServerSandbox.restart_kernel() now asks the server's own
POST /api/kernels/{id}/restart, as _do_interrupt already does.
- check 2 read "cwd is '/home/datalayer', not '/home/datalayer/content'".
The image declares WORKDIR there and the contract's User row requires
it, but a kernel's cwd is the Jupyter server's to choose and
jupyter-python roots it at $HOME. The contract layer now sets
MappingKernelManager.root_dir, which moves the kernel without moving
the file browser. Channel repinned to sha256:122d3e31f5e2....
Also re-pinned the channel digest and apt snapshot in one place: they
were duplicated across two test files and three base releases had left
both red rather than catching anything.
1049 environment/client/jupyter-server tests pass; pre-commit clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… shared engine contents_build is a first-class field on the environment build spec, baked through the same build_commands engine as the spec's uploaded files (build_entries/files_step) on every provider adapter — verified fetch, checksum that fails the build, environment-contents.json manifest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
No description provided.