Skip to content

v1 redesign — tracking issue #11

Description

@thorwhalen

Tracking issue for the v1 redesign. Design docs live in misc/docs/ — architecture.md is the entry point, decisions/ holds ten ADRs.

What v1 is

s3dol becomes a dol-based adapter for S3 and S3-compatible object storage (MinIO, R2, Scaleway, Hetzner, Backblaze, Wasabi, Ceph, Supabase, GCS-interop, Tigris, …), with AWS as the reference semantics. Same shape as azuredol, so one adapter in the family reads like the next.

Three layers: connection (credential + endpoint SSOT, lazy, picklable, redacting) → base (close-to-metal Collection→Reader→Store triads, owns the prefix, one error seam, ObjectHandle) → recipes (factories + codec stacks, by composition only).

Scope: core + large-object I/O. Deferred to v1.x, tracked separately: versions/tags/bucket-config/in-flight-uploads as Mappings, async, fsspec adapter, obstore engine.

Why now — what's actually broken

Verified against the current release:

explicit endpoint_url silently dropped when env credentials exist (base.py:82) store aims at AWS instead of the configured provider
explicit credentials overridden by env (base.py:71) wrong identity, silently
list(store) returns [] on any error (base.py:109) wrong bucket, expired token, missing permission → empty list, no error
writing to a missing bucket creates it — even with make_bucket=False a typo mints a bucket
url_for presigns with SigV2 #10 — rejected by modern S3 and every major alternative
stores are unpicklable unusable with ProcessPoolExecutor or Dask
del store[k] on a missing key silently succeeds; del buckets[name] cascades unpaginated partial, non-idempotent destruction past 1000 objects
anonymous access to public buckets is impossible the entire open-data use case
Supabase support is a per-vendor subclass that hand-parses HTTP chunked framing out of object bodies read-side workaround for a write-side client misconfiguration; corrupts payloads >1 chunk

Most of these share one root cause: credential/endpoint resolution is spread across three functions instead of living in one connection object.

Phases

Compatibility

s3dol.store.S3Store keeps working with its current signature and is removed in v2. It is also the fix delivery mechanism — dependents get corrected endpoint/credential resolution without changing a line.

s3dol/store.py must survive as a module (dependents import the fully-qualified path), bucket_name stays accepted both positionally and by keyword, path= is not renamed, and s3dol/tests/util.py keeps its two functions (py2store imports them under suppress(ImportError), so breaking them fails silently).

Release ordering matters because merging auto-publishes to PyPI and versions burn permanently — see ADR-0007 §5. In particular, the endpoint/credential fix ships separately from the naming/API change so a dependent whose data target moves can bisect it.

Three landmines for anyone picking this up

  1. dol's prefix machinery corrupts non-matching keys — the "obvious" refactor reproduces the bug it was meant to fix. dol#82.
  2. A dol key-wrapper delegates methods with the outer key, so url_for/sub/handle/info/delete_many silently address the wrong object. This is why the prefix lives in the leaf. dol#83.
  3. Never pass EncodingType to a list call — botocore sets it and decodes it, but only when it set it itself.

Activity

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