Skip to content

Make automatic local result persistence opt-in for Jobs.run() #2655

Description

@johnjosephhorton

Problem

Every local Jobs.run() currently enables incremental persistence to EDSL's local content-addressed object store, even when the caller only requests an in-memory Results object. This introduces an implicit filesystem dependency into ordinary execution, including runs with cache=False.

While validating #2648, runner tests and doctests failed with PermissionError: Operation not permitted while creating result blobs under ~/Library/Application Support/edsl/objects/<uuid>/blobs on macOS. The coding environment allowed writes to the repository and temporary directories, but not this application-data directory. Granting filesystem access allowed those tests to proceed. This also means routine tests leave artifacts in the user's normal object store.

The issue is the automatic write itself; changing sandbox permissions or adding a storage-path environment variable would address its location without removing the implicit persistence requirement.

Current implementation

References below use EDSL commit dd1825292afc448ebf86c1fed1c185c93bb84da9:

  • Jobs._execute_with_runner() unconditionally passes stream_to_cas=True to Runner.submit().
  • Runner.submit() already defaults that option to False and creates RunnerCASIntegration only when enabled.
  • JobHandle.results() optionally finalizes streaming, then independently constructs the returned results through JobService.build_edsl_results(). Reading the local persisted copy is not required to return results.
  • ObjectStore.default_root() uses platformdirs.user_data_dir("edsl") / "objects". It currently has no environment-variable override.

Proposed change and scope

Remove the unconditional stream_to_cas=True override from ordinary local Jobs.run() execution. Local runs should return results without automatically creating a versioned copy in the user's object store.

Preserve explicit .ep saving, object-store APIs, and explicitly requested incremental streaming through Runner.submit(stream_to_cas=True). This issue is not a proposal to delete the object-store subsystem, change inference-cache behavior, or remove backend persistence. If streaming should also be exposed through Jobs.run(), make it an explicit option with a default of False.

Document the behavior change: callers relying on automatic local copies must explicitly enable persistence. Do not delete or migrate existing user artifacts as part of this change.

Backend dependency audit

Source inspection of the local expectedparrot/coopr checkout at ca3e23c981080a19a96583b2db69ef4fe39c8cc0 found no dependency on this automatic local copy:

  • Distributed runner: the runner API calls JobService.submit_job() directly, bypassing Jobs.run() and RunnerCASIntegration.
  • Distributed persistence: the writer assembles results from Redis, uploads serialized Results JSON to GCS, and migrates records to PostgreSQL. Its GCS upload does not use EDSL's local object store.
  • Older execution path: remote inference calls Jobs.run(), then explicitly uploads the returned Results via coop.push(). It does not read the automatic local copy.

These are source-level findings, not a deployed-backend integration test. The conclusion applies to disabling automatic local streaming, not removing shared runner storage or serialization APIs. Backend links may require repository access.

Acceptance criteria

  • A normal local job using the test model, with inference caching and remote operations disabled, returns correct answers without constructing RunnerCASIntegration or touching the default ObjectStore directory.
  • Add a regression test that makes access to the default object-store root fail, proving ordinary execution does not depend on it. Check returned results and failure diagnostics as well as filesystem behavior.
  • Explicit incremental streaming still persists results correctly, using an isolated temporary store in its tests.
  • Explicit Results serialization and .ep saving/loading still work, including the response diagnostics from Fix reasoning output budgets and preserve failed-response diagnostics #2648 once integrated.
  • Run affected runner tests and doctests without granting access to the user's normal object store. Isolate tests that intentionally exercise persistence.
  • Update relevant documentation/release notes to explain the new default and the explicit persistence options.

Activity

  1. SahilArate commented on Oct 6, 2026

    @SahilArate

    Hi @johnjosephhorton, I'd like to work on this. The plan:

    1. Remove the unconditional stream_to_cas=True in Jobs._execute_with_runner() so ordinary local runs no longer touch the object store.
    2. Search for any other code that relies on the automatic local copy.
    3. Add a regression test that makes ObjectStore.default_root() fail and checks that results and failure diagnostics are still correct, and that RunnerCASIntegration is not constructed.
    4. Add tests showing explicit stream_to_cas=True and .ep save/load still work, using an isolated temp store.
    5. Update the docs and release notes about the new default.

    I'll keep Jobs.run() without a new streaming parameter in this PR unless you'd prefer one. Could you assign this to me? Thanks!

  2. SahilArate commented on Oct 6, 2026

    @SahilArate

    Hi @johnjosephhorton, the change for this issue is ready on my fork:
    https://github.com/SahilArate/edsl/tree/fix/jobs-run-opt-in-local-persistence

    It removes the unconditional stream_to_cas=True in Jobs._execute_with_runner() and adds a regression test plus a changelog entry. GitHub won't let me open a PR since PRs are limited to collaborators. Could you either add me as a collaborator so I can open it, or let me know how you'd like outside contributions submitted? Happy to adjust anything.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions