> ## Documentation Index
> Fetch the complete documentation index at: https://avala.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Notes

# R2 migration: documentation checks and discrepancies

Checked 2026-09-08. Phase 0 only. These are proposed implementation requirements, not deployed behavior. Official documentation takes precedence over assumptions. The [R2 documentation index](https://developers.cloudflare.com/r2/llms.txt) was fetched first.

## API compatibility

The [S3 compatibility matrix](https://developers.cloudflare.com/r2/api/s3/api/) supports GetObject with Range, HeadObject, ListObjects/ListObjectsV2, PutObject, CopyObject, DeleteObject/DeleteObjects, and multipart create/upload/complete/abort/list operations. Feature-level restrictions still matter. No S3 bucket versioning, object tagging, ACL policy API, replication API, Inventory, or S3 notification configuration equivalence is available. Keep revision identity, ownership, retention and tags in application records; use Cloudflare configuration APIs for infrastructure.

| Existing behavior | Proposed treatment |
| - | - |
| GetObject, Range, HeadObject, ListObjectsV2 | Driver conformance tests, pagination, conditionals, ETag and 206/416 handling |
| PutObject, multipart, CopyObject, DeleteObjects | Fixed parts, bounded concurrency, partial-error handling, same-provider copy; explicit streamed cross-provider copy |
| ListObjectVersions, VersionId, exact-version copy/delete | Immutable revision keys plus application revision mapping; preserve referenced S3 history |
| PutObjectAcl/public-read, bucket policies | Explicit public-release bucket or authenticated edge, never blindly replay ACLs |
| S3 Select, Object Lambda | No compatible replacement assumed; no active call identified in reviewed application paths |
| SSE-KMS, Glacier, replication, tags | Separate security/retention design and approved exceptions; no silent downgrade |
| getUsageForPrefix | Paginated listing plus existing DB ledger |
| setStorageClass | Explicit capability using supported class transition/copy behavior, never arbitrary S3 storage classes |

## Upload protocol and checksum defaults

R2 presigned URLs accept GET, HEAD, PUT and DELETE. HTML form POST upload is unsupported. They expire between one second and seven days and work on the S3 API endpoint, not a custom domain. Existing Avala POST forms must remain supported for old clients and in-flight S3 uploads while a new protocol-aware response is introduced. A hostname rewrite invalidates signing. [Presigned URLs](https://developers.cloudflare.com/r2/api/s3/presigned-urls/).

The current Cloudflare [boto3 example](https://developers.cloudflare.com/r2/examples/aws/boto3/) and [JavaScript v3 example](https://developers.cloudflare.com/r2/examples/aws/aws-sdk-js-v3/) do not mandate `when_required`. The [release notes](https://developers.cloudflare.com/r2/platform/release-notes/) report CRC64NVME support, including full-object multipart checksums, since 2025-07-03. Therefore, a blanket claim that R2 rejects all modern checksums is outdated. The matrix still distinguishes checksum algorithms and full/composite types. Documentation alone does not establish that every installed SDK streaming body works.

Retain the requested R2-only `request_checksum_calculation="when_required"` and `response_checksum_validation="when_required"`, or JS `requestChecksumCalculation: "WHEN_REQUIRED"` and `responseChecksumValidation: "WHEN_REQUIRED"`, as conservative compatibility settings. Verify installed versions and real R2 behavior before promotion, including unknown-length streams and multipart uploads. Keep application SHA-256 validation; disabling automatic optional SDK checksums is not a substitute for integrity verification. [AWS integrity settings](https://docs.aws.amazon.com/sdkref/latest/guide/feature-dataintegrity.html).

Multipart non-final parts must be equally sized, at least 5 MiB, with at most 10,000 parts. Propose a stored 64 MiB part size for ordinary uploads, increased before initialization when total size requires it; never change it mid-upload. Incomplete uploads expire after seven days by default, so the requested one-day abort requires configuration. [Upload objects](https://developers.cloudflare.com/r2/objects/upload-objects/). Apply object/part ceilings from [R2 limits](https://developers.cloudflare.com/r2/platform/limits/); do not proxy multi-GB uploads through Worker request bodies.

## Migration correctness

Sippy is not an exactly-once transfer guarantee: concurrent cache misses can fetch a source multiple times, and objects above 199 MiB may need multiple requests to finish copying. HEAD does not copy. Source overwrites do not refresh an existing R2 copy. Deleting only the R2 object can resurrect the S3 source on a later GET. Only the documented custom metadata is migrated. [Sippy](https://developers.cloudflare.com/r2/data-migration/sippy/).

Propose Sippy only for immutable, collision-free source mappings with application tombstones checked before access. Validate Range and metadata behavior in a cost-bounded canary. Multi-source consolidation and renamed tenant keys need explicit mapping; do not assume a destination bucket can infer which original source bucket owns a key.

Super Slurper defaults to overwrite; select skip-existing for coexistence with new writes. It supports source subpaths and skips objects above 1 TB. Independently reconcile skipped/failed objects and handle larger objects separately. It does not delete the source. [Super Slurper](https://developers.cloudflare.com/r2/data-migration/super-slurper/). Prefix batches and catch-up verification remain necessary for live sources. [Migration strategies](https://developers.cloudflare.com/r2/data-migration/migration-strategies/).

R2 NFC-normalizes keys by default, so two distinct S3 byte strings can collide. Inventory normalized-key collisions before copying; use opaque destination keys with a lossless original-key map, or obtain a documented byte-oriented configuration. Never overwrite one source with another. [Unicode interoperability](https://developers.cloudflare.com/r2/reference/unicode-interoperability/).

## Serving, residency and economics

An R2 public custom domain exposes bucket objects. Private assets require an authenticated Worker/proxy and a private binding, or short-lived S3 API presigns. Do not attach an unguarded public custom domain to managed private buckets. `r2.dev` is for development. [Public buckets](https://developers.cloudflare.com/r2/buckets/public-buckets/).

Location hints are placement preferences, not residency guarantees. Use EU jurisdiction plus the EU endpoint for all EU private classes, including derived and tmp. The existing managed-upload bucket is documented in us-east-1, so `enam` is a candidate; `wnam` remains a candidate for west-coast pipeline workloads. Actual fleet placement and contracts must decide. [Data location](https://developers.cloudflare.com/r2/reference/data-location/).

R2 encrypts at rest and in transit. SSE-C is available, but is not equivalent to AWS KMS key custody or its audit/recovery controls. Determine contractual requirements before replacing the Sessions KMS bucket. EU storage does not by itself make processing on US EC2 EU-resident. [Data security](https://developers.cloudflare.com/r2/reference/data-security/).

R2 Standard costs $0.015/GB-month, Class A $4.50/million and Class B $0.36/million. Infrequent Access costs $0.01/GB-month, Class A $9/million, Class B $0.90/million and retrieval \$0.01/GB, with a 30-day minimum. Egress is free. [Pricing](https://developers.cloudflare.com/r2/pricing/). IA also has a 64 KiB minimum billable object size. Leave derived on Standard until observed access frequency supports a transition. [Storage classes](https://developers.cloudflare.com/r2/buckets/storage-classes/).

R2 events use Cloudflare Queues. Keep explicit upload completion as the primary enqueue path where available, with idempotent recovery for event-driven producers. [Event notifications](https://developers.cloudflare.com/r2/buckets/event-notifications/).

Domain update: the user selected `data.avala.ai` as the preferred serving domain. It is a naming preference, not a DNS change or permission to expose private buckets. The same custom-domain authentication and public-release separation requirements apply.

### Generated integer protocol enum limitation

The upstream `NewDatasetFileUpload.upload_protocol_version` schema correctly uses
`type: integer`, `enum: [2]`, and nullable legacy omission. The pinned
`swagger_dart_code_generator` 4.1.1 generates an `int?` property even though it
also emits an unused protocol enum. In its
`lib/src/code_generators/swagger_models_generator.dart`, `getParameterTypeName`
lines 425 to 440 returns `int` for integer schemas before checking enums; the
enum branch applies only to strings. Keep the integer wire contract. Changing
the schema to string would describe the wrong contract, and a global generator
patch would affect unrelated APIs. Server regressions reject versions 1 and 3;
existing generated wire tests cover integer 2 and null. A future pinned generator
upgrade can adopt integer enums after whole-client compatibility verification.

### Conditional multipart completion requires live verification

Checked 2026-09-10: the R2 [S3 compatibility matrix](https://developers.cloudflare.com/r2/api/s3/api/)
lists CompleteMultipartUpload, but does not explicitly enumerate its destination
conditions. The [extensions](https://developers.cloudflare.com/r2/api/s3/extensions/)
page documents destination conditions for CopyObject, not multipart completion.
Successful ordinary multipart completion does not establish create-only behavior.

The opt-in driver suite now initiates a multipart upload, creates a different
object at that same test key, and requires completion to return a precondition
failure while retaining the original ETag and bytes. This adds one tiny final
part and one tiny object to each selected driver's billable test scope. Cleanup
uses only its recorded test key and upload ID. Offline fixtures validate the
harness; they do not establish actual R2 behavior. Do not activate managed
multipart uploads until the real development-bucket case passes. A failed case
requires a reviewed design change, never removal of the create-only condition.
