Repository: single-cell-data/TileDB-SOMA (language: python)

Issue:
[python/r/c++] Revisit `shape` for component arrays
## PRs

**Merged PRs:**

<details>

* #2909 `kerl/schevo-timestamp-methodize`
* #2913 `kerl/name-neaten`
* #2908 `kerl/ut-soma-exc-simplify`
* #2910 `kerl/test-common-parameterize`
* #2918 `kerl/cpp-test-deadstrip`
* #2919 `kerl/minor-unit-test-helper-mod`
* #2936 `kerl/cpp-ut-helper-neaten`
* #2938 `kerl/more-cur-dom-parameterize`
* #2915 `kerl/cpp-strict-int64-shape`
* #2911 `kerl/arrow-util-current-domain-optional`
* #2939 `kerl/step-two-temp`
* #2947 `kerl/cpp-ndarray-resize-testing`
* #2945 `kerl/dataframe-test-fixture`
* #2944 `kerl/cpp-variant-indexed-dataframes`
* #2916 `kerl/sdf-shape`
* #2917 `kerl/cpp-resizes`
* #2948 `kerl/upgrade-shape-int64`
* #2951 `kerl/sdf-test-accessors`
* #2953 `kerl/py-r-accessor-plumbing`
* #2957 `kerl/sdf-domain-accessors`
* #2960 `kerl/dense-link`
* #2963 `kerl/nightly-fix`
* #2970 `kerl/dense-writeable-after-create`
* #2968 `kerl/minor-trim`
* #2969 `kerl/more-py-domain-name-neaten`
* #2972 `kerl/libtiledbsoma-env-logging-level`
* #2962 `kerl/py-r-creation-paths`
* #2950 `kerl/py-r-test-2`
* #2994 `kerl/nanoarrow-helpers`
* #3011 `kerl/polydom3`
* #3017 `kerl/polydom5`
* #3018 `kerl/polydom6`
* #2990 `kerl/variant-nnz-bug`
* #3019 `kerl/index-swap`
* #3020 `kerl/ut-max-shape`
* #3012 `kerl/polydom4`
* #3025 `kerl/fix-3020-merge`
* #3026 `kerl/one-more-rename`
* #3028 `kerl/ff-not`
* #3029 `kerl/ut-vg`
* #3030 `kerl/table-utils-memory`
* #3067 `kerl/improve-sdf-test-field-names`
* #3068 `kerl/ut-generate`
* #3069 `kerl/cpp-sdf-domain-at-create`
* #3027 `kerl/hll-domainish`
* #3088 `kerl/max-domain-int64`
* #3090 `kerl/maybe-resize-soma-joinid-cpp-tweak`
* #3032 `kerl/sdf-domain-at-create` -- fixes #2967
* #3091 `kerl/maybe-resize-soma-joinid-py-r`
* #3095 `kerl/cpp-exp-resize-prep`
* #3089 `kerl/r-dataframe-shapeable`
* https://github.com/single-cell-data/SOMA/pull/233
* #3125 `kerl/cpp-ut-name-shortens`
* #3127 `kerl/helper-rename`
* #3130 `kerl/cpp-can-resizers-names`
* #3132 `kerl/cpp-dataframe-sizing-helpers`
* #3139 `kerl/cpp-dataframe-upgrade-test`
* #3140 `kerl/py-resizer-connects`
* #3151 `kerl/py-can-upgrade-shape`
* #3152 `kerl/registration-shape-acceessors`
* #3156 `kerl/py-exp-shaping`
* #3157 `kerl/py-exp-shaping2`
* #3148 `kerl/py-exp-resize`
* #3191 `kerl/py-domain-at-create-ut-1`
* #3190 `kerl/py-domain-at-create-ut-2`
* #3192 `kerl/py-domain-at-create-ut-3`
* #3193 `kerl/py-domain-at-create-ut-4`
* #3194 `kerl/py-domain-at-create-ut-5`
* #3203 `kerl/min-size-2`
* #3208 `kerl/r-min-sizing`
* #3211 `kerl/cpp-ugr-dom`
* #3232 `kerl/ff-interop`
* #3230 `kerl/ffon`
* #3234 `kerl/docstring-prune`
* #3236 `kerl/prefixing`
* #3241 `kerl/fix-bad-merge`
* #3235 `kerl/py-r-ugr-dom`
* #3237 `kerl/py-r-ugr-dom-2`
* #3238 `kerl/py-r-ugr-dom-3`
* #3253 `kerl/set-coords-rename`
* #3261 `kerl/pybind11-nda-sizing`
* #3265 `kerl/dense-227-a`
* #3263 `kerl/dense-range-trim`
* #3268 `kerl/dim-explosion`
* #3269 `kerl/python-227-dense-ned-read`
* #3270 `kerl/r-227-dense-fixes`
* #3280 `kerl/r-dense-227-more`
* #3286 `kerl/more-fn4m`
* #3283 `kerl/readthedocs-pre-1.15`
* #3288 `kerl/dense-ugrsh`
* #3289 `kerl/notebook-shape-upgrade`
* #3285 `kerl/new-shape-doc-updates`
* #3295 `kerl/notebook-data-refresh`
* #3290 `kerl/notebook-new-shape-refresh`
* #3301 `kerl/ffena`
* #3303 `kerl/r-data-refresh`
* #3300 `kerl/sdf-sjid-lower-zero`
* #3296 `kerl/dense-example-data-refresh`
* #3294 `kerl/new-shape-notebook-and-vignette`
* #3308 `kerl/upgrade-experiment-resources`
* #3309 `kerl/fix-notebook-merge`
* #3321 `kerl/more-use-shape`
* #3358 `kerl/revert-3300`
* #3368 `kerl/227a`
* #3369 `kerl/ucd1`
* #3370 `kerl/ucd2`
* #3371 `kerl/ucd3`
* #3372 `kerl/ucd4`
* #3396 `kerl/domain-at-create-docstrings`
* #3302 `kerl/new-shape-vignette`
* https://github.com/single-cell-data/SOMA/pull/250
* #3399 `kerl/new-shape-more-docstrings`
* #3400 `kerl/check-only-r`
* https://github.com/TileDB-Inc/somacore-feedstock/pull/27

</details>

**Closed/abandoned PRs:**

<details>

* #2785 -- This was only dogfooding for the core 2.25 release -- not to be merged
* #2952 `kerl/feature-flag-temp` -- folded into 2962
* #2995 `kerl/polydom`
* #2964 `kerl/tiledbsoma-io-test`
* #3189 `kerl/min-size`
* #3220 `kerl/cpp-ugr-dom-2`
* #3244 `kerl/dense-227-fixes`
* #3276 `kerl/dataframe-shape`

</details>

**Issues which are related but non-blocking:**

* https://github.com/single-cell-data/SOMA/pull/216
* https://github.com/TileDB-Inc/TileDB/pull/5303
* #2966
* #3081
* Note: R append mode does not exist yet -- see #1630 -- so an experiment-level resizer is not a priority in R
* #3271 
* #3272
* #3273

**See also:** [[sc-51048]](https://app.shortcut.com/tiledb-inc/story/51048).

## Problem to be solved

Users want to know the `shape` of an array, in the SciPy sense:

* Reads and writes are bounds-checked against the shape
* This retains its value regardless of which values of a sparse array are or are not actually occupied
* Users can `resize`.
  * Some users need the ability to grow their datasets later, using either `tiledbsoma.io`'s append mode, or subsequent writes using the `tiledbsoma` API.
  * Note that the cellxgene census doesn't need this: eact week's published census has fixed shape, and any updates will happen in new storage, on a new week.

Using TileDB-SOMA up until the present:

* The TIleDB `domain` is immutable after array creation
  * This does bounds-checking for reads and writes, which is good
  * To leverage this to function as a `shape`, users would need to set the `domain` at array-creation time. However, users lose the ability to grow their datasets later.
* There is a `non_empty_domain` accessor
  * This only indicates min/max coordinates _at which data exists_. Consider an `X` array for 100 cells and 200 genes. If non-zero expression counts exist only for cell join IDs 2-17, then the `non_empty_domain` will indicate `(2,17)` along `soma_dim_0`.
  * Consider an `obms["X_pca"]` within the same experiment. This may be 100 cells by 50 PCA components: we need a placd to store the number 50.
  * Therefore users cannot leverage this to function as a `shape` accessor.
* We have offered a `used_shape` accessor since TileDB-SOMA 1.5.
  * This functions as a `shape` accessor, in the SciPy sense, but it is not multi-writer safe.

New feature for TileDB-SOMA 1.15:

* Arrays will have a  `shape`
* Reads and writes are bounds-checked against the shape
* This retains its value regardless of which values of a sparse array are or are not actually occupied
* Users can `resize`
* The `used_shape` accessor will be deprecated in TileDB-SOMA 1.13, and slated for removal in TileDB-SOMA 1.14.

Compatiblity:

This will now require users to do an explicit `resize` before appending/growing TileDB-SOMA Experiments. Guidance in the form of example notebooks will be provided.

##  Tracking

See also: [[sc-41074]](https://app.shortcut.com/tiledb-inc/story/41074) and [[sc-51048]](https://app.shortcut.com/tiledb-inc/story/51048).

## Scheduling

Support arrives in TileDB Core 2.25. Deprecations for TileDB-SOMA will be released with 1.13. Full support within TileDB-SOMA will be release in 1.14.

## Details

SOMA API mods as we've discussed in a Google doc are as follows.

### `SOMADataFrame`

* `create`: Retain the `domain` argument
  * Issue:
    * Core has a `(lo, hi)` tuple per dim, e.g. `(0,99)` or `(10,19)`
    * SOMA has count per dim, with 0 implicit: e.g. 100 or 20
    * For `SparseNDArray` and `DenseNDArray` core can have `(lo, hi)` and SOMA can have `count`
    * For `DataFrame` there can be multiple dims --- default is a single `soma_joinid`
    * That could be treated either in `(lo, hi)` fashion or `count` fashion
    * However additional dims (e.g. `cell_type`) can be on any type, including strings, floats, etc. where there is no implicit lo=0
    * Therefore we need to keep the current SOMA API wherein `DataFrame` takes a `domain` argument (in `(lo, hi)` fashion) and not a `shape` argument (in `count` fashion)

### `SparseNDArray and DenseNDArray`

* `create`
  * Have an optional shape argument which is of type `Tuple[Int,...]` where each element is the cell count of the corresponding dimension
    * If unsupplied, or if supplied but None in any slot: use the minimum 0 in each slot – nothing larger makes sense since we will not support downsize
  * User guidance should make clear that it will not be possible to create an ‘old’ style array with the ‘new style’ API. (See also the upgrade logic below.)

### All three of `SOMADataFrame`, `SparseNDArray`, `DenseNDArray`

* `write`
  * For new arrays, created with the new shape feature:
    * Core will bounds-check that coordinates provided at `write` time are within the current shape
    * Core will raise `tiledb.cc.TileDBError` to TileDB-SOMA, which will catch and raise `IndexError`, and R-standard behavior on the R side
  * For old arrays created before this feature:
    * Core will not bounds-check that coordinates provided at write time are within the current shape
* Existing `used_shape` accessor
  * TileDB-SOMA will deprecate this over a release cycle.
  * For new arrays: raise `NotImplementedError`
  * For old arrays: return what’s currently returned, with a deprecation warning.
  * Mechanism for determining old vs. new: `array.schema.version` (the core storage version).
* Existing `shape` accessor
  * For new arrays:
    * Have this return the new shape as proposed by core, no longer returning the TileDB domain.
  * For old arrays created before this feature:
    * Return the TileDB domain as now.
* Existing `non_empty_domain` accessor
  * Same behavior for old and new arrays (unaffected by this proposal).
  * Keep this accessor supported, but, with user notes that it’s generally non-useful
  * This should return None (or R equivalent) when there is a schema but no data have been written.
* New `maxshape` accessor
  * Maps the core-level `(lo, hi)` accessor for domain to count-style accessor hi+1. E.g. if the core domain is either `(0,99)` or `(50,99)` then TileDB-SOMA `maxshape` will say 100.
  * Same behavior for old and new arrays.
  * Let users query for what the TileDB domain is, with user notes that it’s the maximum that users can reshape to.
  * Issac suggests: maybe `domain` or `maxshape` (see h5py).
* New `resize` mutator
  * Note: `reshape` means something else in the community (numpy, zarr, h5py), e.g. a 5x20 (total 100 cells) being reinterpreted as 4x25 (still 100 cells). The standard name for changing cell-count is `resize`.
  * For old arrays created before this feature: raise `NotImplementedError`.
  * For new arrays:
    * Will raise `ValueError` if the new shape is smaller on any dim than currently in storage
    * Regardless of whether any data have been written whatsoever
    * Will raise `ValueError` if the new shape exceeds the TileDB domain from create time, which will serve TileDB-SOMA in a role of “max possible shape the user can reshape to”
    * Otherwise, any calls to write from this point will bounds-check writes within this new shape
    * **We don’t expect resize to be multi-writer safe with regard to write ; user notes must be clear on this point**
* New `tiledbsoma_upgrade_shape` method for SparseNDArray and DenseNDArray
  * This will leverage `array.schema.version` to see if an upgrade is needed
  * Leverage core support for storage-version updates
  * This will take a shape argument as in `create`
  * For arrays created with “just-right” size: this will succeed
  * For arrays created with “room-for-growth” / “two billion-ish” size: this will succeed
  * If the user passes a shape which exceeds the current TileDB domain: this will fail
* New `tiledbsoma_upgrade_domain method` for `DataFrame`
  * Same as for `SparseNDArray`/`DenseNDArray` except it will take a domain at the SOMA-API level just as `DataFrame`'s create method

### `tiledbsoma.io`

* The user-facing API has no shape arguments and thus won’t need changing.
* Internally to `tiledbsoma.io`, we’ll still ask the tiledbsoma API for the “big domain” (2 billionish)
* Append mode:
  * Will need a new `resize` method at the `Experiment` level
  * Users will need to:
    * Register as now
    * Call the experiment-level `resize`
      * Could be `exp.resize(...)`, or (better) this could be `tiledbsoma.io.reshape_experiment`
  * In either case: this method will take the new `obs` and `var` counts as inputs:
    * `exp.obs.reshape` to new `obs` count
    * `exp.ms[name].var.reshape` to new `var` count
    * `exp.ms[name].X[name].reshape` to new `obs` count x `var` count
    * `exp.ms[name].obsm[name].reshape` to new `obs` count x same width
    * `exp.ms[name].obsp[name].reshape` to new `obs` count x `obs` count
    * `exp.ms[name].varm[name].reshape` to new `var` count x same width
    * `exp.ms[name].varp[name].reshape` to new `var` count x `var` count
  * Do the individual append-mode writes as now

[c++/r/python] Embrace new-shape feature flag
Follow-on work to #2407.

* Remove the feature-flag detection in Python/R
* Remove feature-flag=off unit-test bits
  * Note that we still do have canned old-style experiments as `.tgz` so we can test old-style arrays -- nothing is lost
* Remove `libtilebsoma` support for schema tables with 3 rows -- insist on 5 now

This can't be done until we depend on core 2.27 since only then will we have current-domain support for dense arrays.


[python/r/c++] Revisit `shape` for component arrays
## PRs

**Merged PRs:**

<details>

* #2909 `kerl/schevo-timestamp-methodize`
* #2913 `kerl/name-neaten`
* #2908 `kerl/ut-soma-exc-simplify`
* #2910 `kerl/test-common-parameterize`
* #2918 `kerl/cpp-test-deadstrip`
* #2919 `kerl/minor-unit-test-helper-mod`
* #2936 `kerl/cpp-ut-helper-neaten`
* #2938 `kerl/more-cur-dom-parameterize`
* #2915 `kerl/cpp-strict-int64-shape`
* #2911 `kerl/arrow-util-current-domain-optional`
* #2939 `kerl/step-two-temp`
* #2947 `kerl/cpp-ndarray-resize-testing`
* #2945 `kerl/dataframe-test-fixture`
* #2944 `kerl/cpp-variant-indexed-dataframes`
* #2916 `kerl/sdf-shape`
* #2917 `kerl/cpp-resizes`
* #2948 `kerl/upgrade-shape-int64`
* #2951 `kerl/sdf-test-accessors`
* #2953 `kerl/py-r-accessor-plumbing`
* #2957 `kerl/sdf-domain-accessors`
* #2960 `kerl/dense-link`
* #2963 `kerl/nightly-fix`
* #2970 `kerl/dense-writeable-after-create`
* #2968 `kerl/minor-trim`
* #2969 `kerl/more-py-domain-name-neaten`
* #2972 `kerl/libtiledbsoma-env-logging-level`
* #2962 `kerl/py-r-creation-paths`
* #2950 `kerl/py-r-test-2`
* #2994 `kerl/nanoarrow-helpers`
* #3011 `kerl/polydom3`
* #3017 `kerl/polydom5`
* #3018 `kerl/polydom6`
* #2990 `kerl/variant-nnz-bug`
* #3019 `kerl/index-swap`
* #3020 `kerl/ut-max-shape`
* #3012 `kerl/polydom4`
* #3025 `kerl/fix-3020-merge`
* #3026 `kerl/one-more-rename`
* #3028 `kerl/ff-not`
* #3029 `kerl/ut-vg`
* #3030 `kerl/table-utils-memory`
* #3067 `kerl/improve-sdf-test-field-names`
* #3068 `kerl/ut-generate`
* #3069 `kerl/cpp-sdf-domain-at-create`
* #3027 `kerl/hll-domainish`
* #3088 `kerl/max-domain-int64`
* #3090 `kerl/maybe-resize-soma-joinid-cpp-tweak`
* #3032 `kerl/sdf-domain-at-create` -- fixes #2967
* #3091 `kerl/maybe-resize-soma-joinid-py-r`
* #3095 `kerl/cpp-exp-resize-prep`
* #3089 `kerl/r-dataframe-shapeable`
* https://github.com/single-cell-data/SOMA/pull/233
* #3125 `kerl/cpp-ut-name-shortens`
* #3127 `kerl/helper-rename`
* #3130 `kerl/cpp-can-resizers-names`
* #3132 `kerl/cpp-dataframe-sizing-helpers`
* #3139 `kerl/cpp-dataframe-upgrade-test`
* #3140 `kerl/py-resizer-connects`
* #3151 `kerl/py-can-upgrade-shape`
* #3152 `kerl/registration-shape-acceessors`
* #3156 `kerl/py-exp-shaping`
* #3157 `kerl/py-exp-shaping2`
* #3148 `kerl/py-exp-resize`
* #3191 `kerl/py-domain-at-create-ut-1`
* #3190 `kerl/py-domain-at-create-ut-2`
* #3192 `kerl/py-domain-at-create-ut-3`
* #3193 `kerl/py-domain-at-create-ut-4`
* #3194 `kerl/py-domain-at-create-ut-5`
* #3203 `kerl/min-size-2`
* #3208 `kerl/r-min-sizing`
* #3211 `kerl/cpp-ugr-dom`
* #3232 `kerl/ff-interop`
* #3230 `kerl/ffon`
* #3234 `kerl/docstring-prune`
* #3236 `kerl/prefixing`
* #3241 `kerl/fix-bad-merge`
* #3235 `kerl/py-r-ugr-dom`
* #3237 `kerl/py-r-ugr-dom-2`
* #3238 `kerl/py-r-ugr-dom-3`
* #3253 `kerl/set-coords-rename`
* #3261 `kerl/pybind11-nda-sizing`
* #3265 `kerl/dense-227-a`
* #3263 `kerl/dense-range-trim`
* #3268 `kerl/dim-explosion`
* #3269 `kerl/python-227-dense-ned-read`
* #3270 `kerl/r-227-dense-fixes`
* #3280 `kerl/r-dense-227-more`
* #3286 `kerl/more-fn4m`
* #3283 `kerl/readthedocs-pre-1.15`
* #3288 `kerl/dense-ugrsh`
* #3289 `kerl/notebook-shape-upgrade`
* #3285 `kerl/new-shape-doc-updates`
* #3295 `kerl/notebook-data-refresh`
* #3290 `kerl/notebook-new-shape-refresh`
* #3301 `kerl/ffena`
* #3303 `kerl/r-data-refresh`
* #3300 `kerl/sdf-sjid-lower-zero`
* #3296 `kerl/dense-example-data-refresh`
* #3294 `kerl/new-shape-notebook-and-vignette`
* #3308 `kerl/upgrade-experiment-resources`
* #3309 `kerl/fix-notebook-merge`
* #3321 `kerl/more-use-shape`
* #3358 `kerl/revert-3300`
* #3368 `kerl/227a`
* #3369 `kerl/ucd1`
* #3370 `kerl/ucd2`
* #3371 `kerl/ucd3`
* #3372 `kerl/ucd4`
* #3396 `kerl/domain-at-create-docstrings`
* #3302 `kerl/new-shape-vignette`
* https://github.com/single-cell-data/SOMA/pull/250
* #3399 `kerl/new-shape-more-docstrings`
* #3400 `kerl/check-only-r`
* https://github.com/TileDB-Inc/somacore-feedstock/pull/27

</details>

**Closed/abandoned PRs:**

<details>

* #2785 -- This was only dogfooding for the core 2.25 release -- not to be merged
* #2952 `kerl/feature-flag-temp` -- folded into 2962
* #2995 `kerl/polydom`
* #2964 `kerl/tiledbsoma-io-test`
* #3189 `kerl/min-size`
* #3220 `kerl/cpp-ugr-dom-2`
* #3244 `kerl/dense-227-fixes`
* #3276 `kerl/dataframe-shape`

</details>

**Issues which are related but non-blocking:**

* https://github.com/single-cell-data/SOMA/pull/216
* https://github.com/TileDB-Inc/TileDB/pull/5303
* #2966
* #3081
* Note: R append mode does not exist yet -- see #1630 -- so an experiment-level resizer is not a priority in R
* #3271 
* #3272
* #3273

**See also:** [[sc-51048]](https://app.shortcut.com/tiledb-inc/story/51048).

## Problem to be solved

Users want to know the `shape` of an array, in the SciPy sense:

* Reads and writes are bounds-checked against the shape
* This retains its value regardless of which values of a sparse array are or are not actually occupied
* Users can `resize`.
  * Some users need the ability to grow their datasets later, using either `tiledbsoma.io`'s append mode, or subsequent writes using the `tiledbsoma` API.
  * Note that the cellxgene census doesn't need this: eact week's published census has fixed shape, and any updates will happen in new storage, on a new week.

Using TileDB-SOMA up until the present:

* The TIleDB `domain` is immutable after array creation
  * This does bounds-checking for reads and writes, which is good
  * To leverage this to function as a `shape`, users would need to set the `domain` at array-creation time. However, users lose the ability to grow their datasets later.
* There is a `non_empty_domain` accessor
  * This only indicates min/max coordinates _at which data exists_. Consider an `X` array for 100 cells and 200 genes. If non-zero expression counts exist only for cell join IDs 2-17, then the `non_empty_domain` will indicate `(2,17)` along `soma_dim_0`.
  * Consider an `obms["X_pca"]` within the same experiment. This may be 100 cells by 50 PCA components: we need a placd to store the number 50.
  * Therefore users cannot leverage this to function as a `shape` accessor.
* We have offered a `used_shape` accessor since TileDB-SOMA 1.5.
  * This functions as a `shape` accessor, in the SciPy sense, but it is not multi-writer safe.

New feature for TileDB-SOMA 1.15:

* Arrays will have a  `shape`
* Reads and writes are bounds-checked against the shape
* This retains its value regardless of which values of a sparse array are or are not actually occupied
* Users can `resize`
* The `used_shape` accessor will be deprecated in TileDB-SOMA 1.13, and slated for removal in TileDB-SOMA 1.14.

Compatiblity:

This will now require users to do an explicit `resize` before appending/growing TileDB-SOMA Experiments. Guidance in the form of example notebooks will be provided.

##  Tracking

See also: [[sc-41074]](https://app.shortcut.com/tiledb-inc/story/41074) and [[sc-51048]](https://app.shortcut.com/tiledb-inc/story/51048).

## Scheduling

Support arrives in TileDB Core 2.25. Deprecations for TileDB-SOMA will be released with 1.13. Full support within TileDB-SOMA will be release in 1.14.

## Details

SOMA API mods as we've discussed in a Google doc are as follows.

### `SOMADataFrame`

* `create`: Retain the `domain` argument
  * Issue:
    * Core has a `(lo, hi)` tuple per dim, e.g. `(0,99)` or `(10,19)`
    * SOMA has count per dim, with 0 implicit: e.g. 100 or 20
    * For `SparseNDArray` and `DenseNDArray` core can have `(lo, hi)` and SOMA can have `count`
    * For `DataFrame` there can be multiple dims --- default is a single `soma_joinid`
    * That could be treated either in `(lo, hi)` fashion or `count` fashion
    * However additional dims (e.g. `cell_type`) can be on any type, including strings, floats, etc. where there is no implicit lo=0
    * Therefore we need to keep the current SOMA API wherein `DataFrame` takes a `domain` argument (in `(lo, hi)` fashion) and not a `shape` argument (in `count` fashion)

### `SparseNDArray and DenseNDArray`

* `create`
  * Have an optional shape argument which is of type `Tuple[Int,...]` where each element is the cell count of the corresponding dimension
    * If unsupplied, or if supplied but None in any slot: use the minimum 0 in each slot – nothing larger makes sense since we will not support downsize
  * User guidance should make clear that it will not be possible to create an ‘old’ style array with the ‘new style’ API. (See also the upgrade logic below.)

### All three of `SOMADataFrame`, `SparseNDArray`, `DenseNDArray`

* `write`
  * For new arrays, created with the new shape feature:
    * Core will bounds-check that coordinates provided at `write` time are within the current shape
    * Core will raise `tiledb.cc.TileDBError` to TileDB-SOMA, which will catch and raise `IndexError`, and R-standard behavior on the R side
  * For old arrays created before this feature:
    * Core will not bounds-check that coordinates provided at write time are within the current shape
* Existing `used_shape` accessor
  * TileDB-SOMA will deprecate this over a release cycle.
  * For new arrays: raise `NotImplementedError`
  * For old arrays: return what’s currently returned, with a deprecation warning.
  * Mechanism for determining old vs. new: `array.schema.version` (the core storage version).
* Existing `shape` accessor
  * For new arrays:
    * Have this return the new shape as proposed by core, no longer returning the TileDB domain.
  * For old arrays created before this feature:
    * Return the TileDB domain as now.
* Existing `non_empty_domain` accessor
  * Same behavior for old and new arrays (unaffected by this proposal).
  * Keep this accessor supported, but, with user notes that it’s generally non-useful
  * This should return None (or R equivalent) when there is a schema but no data have been written.
* New `maxshape` accessor
  * Maps the core-level `(lo, hi)` accessor for domain to count-style accessor hi+1. E.g. if the core domain is either `(0,99)` or `(50,99)` then TileDB-SOMA `maxshape` will say 100.
  * Same behavior for old and new arrays.
  * Let users query for what the TileDB domain is, with user notes that it’s the maximum that users can reshape to.
  * Issac suggests: maybe `domain` or `maxshape` (see h5py).
* New `resize` mutator
  * Note: `reshape` means something else in the community (numpy, zarr, h5py), e.g. a 5x20 (total 100 cells) being reinterpreted as 4x25 (still 100 cells). The standard name for changing cell-count is `resize`.
  * For old arrays created before this feature: raise `NotImplementedError`.
  * For new arrays:
    * Will raise `ValueError` if the new shape is smaller on any dim than currently in storage
    * Regardless of whether any data have been written whatsoever
    * Will raise `ValueError` if the new shape exceeds the TileDB domain from create time, which will serve TileDB-SOMA in a role of “max possible shape the user can reshape to”
    * Otherwise, any calls to write from this point will bounds-check writes within this new shape
    * **We don’t expect resize to be multi-writer safe with regard to write ; user notes must be clear on this point**
* New `tiledbsoma_upgrade_shape` method for SparseNDArray and DenseNDArray
  * This will leverage `array.schema.version` to see if an upgrade is needed
  * Leverage core support for storage-version updates
  * This will take a shape argument as in `create`
  * For arrays created with “just-right” size: this will succeed
  * For arrays created with “room-for-growth” / “two billion-ish” size: this will succeed
  * If the user passes a shape which exceeds the current TileDB domain: this will fail
* New `tiledbsoma_upgrade_domain method` for `DataFrame`
  * Same as for `SparseNDArray`/`DenseNDArray` except it will take a domain at the SOMA-API level just as `DataFrame`'s create method

### `tiledbsoma.io`

* The user-facing API has no shape arguments and thus won’t need changing.
* Internally to `tiledbsoma.io`, we’ll still ask the tiledbsoma API for the “big domain” (2 billionish)
* Append mode:
  * Will need a new `resize` method at the `Experiment` level
  * Users will need to:
    * Register as now
    * Call the experiment-level `resize`
      * Could be `exp.resize(...)`, or (better) this could be `tiledbsoma.io.reshape_experiment`
  * In either case: this method will take the new `obs` and `var` counts as inputs:
    * `exp.obs.reshape` to new `obs` count
    * `exp.ms[name].var.reshape` to new `var` count
    * `exp.ms[name].X[name].reshape` to new `obs` count x `var` count
    * `exp.ms[name].obsm[name].reshape` to new `obs` count x same width
    * `exp.ms[name].obsp[name].reshape` to new `obs` count x `obs` count
    * `exp.ms[name].varm[name].reshape` to new `var` count x same width
    * `exp.ms[name].varp[name].reshape` to new `var` count x `var` count
  * Do the individual append-mode writes as now



Discussion / hints:
#2785 is a quick-and-dirty concept-prover -- its sole function is to flush out any API misunderstandings we might have, in prep for 2.25.0 core release.

#2785 is a quick-and-dirty concept-prover -- its sole function is to flush out any API misunderstandings we might have, in prep for 2.25.0 core release.

Fix patch:
diff --git a/libtiledbsoma/src/utils/arrow_adapter.cc b/libtiledbsoma/src/utils/arrow_adapter.cc
index a2edb4ac5b..d601719abf 100644
--- a/libtiledbsoma/src/utils/arrow_adapter.cc
+++ b/libtiledbsoma/src/utils/arrow_adapter.cc
@@ -954,8 +954,6 @@ ArraySchema ArrowAdapter::tiledb_schema_from_arrow_schema(
 
     std::map<std::string, Dimension> dims;
 
-    bool use_current_domain = true;
-
     for (int64_t sch_idx = 0; sch_idx < arrow_schema->n_children; ++sch_idx) {
         auto child = arrow_schema->children[sch_idx];
         std::string_view type_metadata;
@@ -1059,105 +1057,95 @@ ArraySchema ArrowAdapter::tiledb_schema_from_arrow_schema(
 
     // Note: this must be done after we've got the core domain, since the
     // NDRectangle constructor requires access to the core domain.
-    if (use_current_domain) {
-        CurrentDomain current_domain(*ctx);
-        NDRectangle ndrect(*ctx, domain);
-
-        for (int64_t sch_idx = 0; sch_idx < arrow_schema->n_children;
-             ++sch_idx) {
-            auto child = arrow_schema->children[sch_idx];
-            auto type = ArrowAdapter::to_tiledb_format(child->format);
-
-            for (int64_t i = 0; i < index_column_schema->n_children; ++i) {
-                auto col_name = index_column_schema->children[i]->name;
-                if (strcmp(child->name, col_name) != 0) {
-                    continue;
-                }
 
-                if (strcmp(child->name, SOMA_GEOMETRY_COLUMN_NAME.c_str()) ==
-                        0 &&
-                    spatial_column_info.first.get() != nullptr) {
-                    for (int64_t j = 0;
-                         j < spatial_column_info.first->n_children;
-                         ++j) {
-                        auto col_name = SOMA_GEOMETRY_DIMENSION_PREFIX +
-                                        std::string(spatial_column_info.second
-                                                        ->children[j]
-                                                        ->name);
-                        const void* buff = spatial_column_info.first
-                                               ->children[j]
-                                               ->buffers[1];
-                        auto type = ArrowAdapter::to_tiledb_format(
-                            spatial_column_info.second->children[j]->format);
-
-                        _set_current_domain_slot(
-                            type, buff, ndrect, col_name + "__min");
-                        _set_current_domain_slot(
-                            type, buff, ndrect, col_name + "__max");
-                    }
-                } else if (ArrowAdapter::arrow_is_var_length_type(
-                               child->format)) {
-                    // In the core API:
-                    //
-                    // * domain for strings must be set as (nullptr, nullptr)
-                    // * current_domain for strings cannot be set as (nullptr,
-                    //   nullptr)
-                    //
-                    // Fortunately, these are ASCII dims and we can range
-                    // these accordingly.
-
-                    ArrowArray* child_array = index_column_array->children[i];
-                    ArrowSchema* child_schema = index_column_schema
-                                                    ->children[i];
-
-                    std::vector<std::string>
-                        strings = ArrowAdapter::get_array_string_column(
-                            child_array, child_schema);
-                    if (strings.size() != 5) {
-                        throw TileDBSOMAError(std::format(
-                            "ArrowAdapter::tiledb_schema_from_arrow_schema: "
-                            "internal error: "
-                            "expected 5 strings, got {}",
-                            strings.size()));
-                    }
-
-                    std::string lo = strings[3];
-                    std::string hi = strings[4];
-                    if (lo == "" && hi == "") {
-                        // These mean "I the caller don't care, you
-                        // libtiledbsoma make it as big as possible".
-                        // See also comments in soma_array.h.
-                        ndrect.set_range(col_name, "", "\x7f");
-                    } else {
-                        ndrect.set_range(col_name, lo, hi);
-                        LOG_DEBUG(std::format(
-                            "[ArrowAdapter] index_column_info nbuf {}",
-                            index_column_array->children[i]->n_buffers));
-                    }
+    CurrentDomain current_domain(*ctx);
+    NDRectangle ndrect(*ctx, domain);
 
-                    LOG_DEBUG(std::format(
-                        "[ArrowAdapter] current domain {} \"{}\"-\"{}\"",
-                        child_schema->name,
-                        lo,
-                        hi));
-                } else {
-                    const void* buff = index_column_array->children[i]
+    for (int64_t sch_idx = 0; sch_idx < arrow_schema->n_children; ++sch_idx) {
+        auto child = arrow_schema->children[sch_idx];
+        auto type = ArrowAdapter::to_tiledb_format(child->format);
+
+        for (int64_t i = 0; i < index_column_schema->n_children; ++i) {
+            auto col_name = index_column_schema->children[i]->name;
+            if (strcmp(child->name, col_name) != 0) {
+                continue;
+            }
+
+            if (strcmp(child->name, SOMA_GEOMETRY_COLUMN_NAME.c_str()) == 0 &&
+                spatial_column_info.first.get() != nullptr) {
+                for (int64_t j = 0; j < spatial_column_info.first->n_children;
+                     ++j) {
+                    auto col_name = SOMA_GEOMETRY_DIMENSION_PREFIX +
+                                    std::string(
+                                        spatial_column_info.second->children[j]
+                                            ->name);
+                    const void* buff = spatial_column_info.first->children[j]
                                            ->buffers[1];
-                    _set_current_domain_slot(type, buff, ndrect, col_name);
+                    auto type = ArrowAdapter::to_tiledb_format(
+                        spatial_column_info.second->children[j]->format);
+
+                    _set_current_domain_slot(
+                        type, buff, ndrect, col_name + "__min");
+                    _set_current_domain_slot(
+                        type, buff, ndrect, col_name + "__max");
                 }
-                break;
+            } else if (ArrowAdapter::arrow_is_var_length_type(child->format)) {
+                // In the core API:
+                //
+                // * domain for strings must be set as (nullptr, nullptr)
+                // * current_domain for strings cannot be set as (nullptr,
+                //   nullptr)
+                //
+                // Fortunately, these are ASCII dims and we can range
+                // these accordingly.
+
+                ArrowArray* child_array = index_column_array->children[i];
+                ArrowSchema* child_schema = index_column_schema->children[i];
+
+                std::vector<std::string>
+                    strings = ArrowAdapter::get_array_string_column(
+                        child_array, child_schema);
+                if (strings.size() != 5) {
+                    throw TileDBSOMAError(std::format(
+                        "ArrowAdapter::tiledb_schema_from_arrow_schema: "
+                        "internal error: "
+                        "expected 5 strings, got {}",
+                        strings.size()));
+                }
+
+                std::string lo = strings[3];
+                std::string hi = strings[4];
+                if (lo == "" && hi == "") {
+                    // These mean "I the caller don't care, you
+                    // libtiledbsoma make it as big as possible"
+                    ndrect.set_range(col_name, "", "\x7f");
+                } else {
+                    ndrect.set_range(col_name, lo, hi);
+                    LOG_DEBUG(std::format(
+                        "[ArrowAdapter] index_column_info nbuf {}",
+                        index_column_array->children[i]->n_buffers));
+                }
+
+                LOG_DEBUG(std::format(
+                    "[ArrowAdapter] current domain {} \"{}\"-\"{}\"",
+                    child_schema->name,
+                    lo,
+                    hi));
+            } else {
+                const void* buff = index_column_array->children[i]->buffers[1];
+                _set_current_domain_slot(type, buff, ndrect, col_name);
             }
+            break;
         }
+    }
 
-        current_domain.set_ndrectangle(ndrect);
+    current_domain.set_ndrectangle(ndrect);
 
-        LOG_DEBUG(std::format(
-            "[ArrowAdapter] before setting current_domain from ndrect"));
-        ArraySchemaExperimental::set_current_domain(
-            *ctx, schema, current_domain);
-        LOG_DEBUG(std::format(
-            "[ArrowAdapter] after setting current_domain from ndrect"));
-    }
+    LOG_DEBUG(std::format(
+        "[ArrowAdapter] before setting current_domain from ndrect"));
+    ArraySchemaExperimental::set_current_domain(*ctx, schema, current_domain);
+    LOG_DEBUG(
+        std::format("[ArrowAdapter] after setting current_domain from ndrect"));
 
     LOG_DEBUG(std::format("[ArrowAdapter] check"));
     schema.check();


Test patch:
diff --git a/libtiledbsoma/test/common.cc b/libtiledbsoma/test/common.cc
index 8b3ffb4c85..d194626783 100644
--- a/libtiledbsoma/test/common.cc
+++ b/libtiledbsoma/test/common.cc
@@ -124,11 +124,10 @@ create_arrow_schema_and_index_columns(
 ArrowTable create_column_index_info(const std::vector<DimInfo>& dim_infos) {
     for (auto info : dim_infos) {
         LOG_DEBUG(std::format(
-            "create_column_index_info name={} type={} dim_max={} ucd={}",
+            "create_column_index_info name={} type={} dim_max={}",
             info.name,
             tiledb::impl::to_str(info.tiledb_datatype),
-            info.dim_max,
-            info.use_current_domain));
+            info.dim_max));
     }
 
     auto index_cols_info_schema = create_index_cols_info_schema(dim_infos);
diff --git a/libtiledbsoma/test/common.h b/libtiledbsoma/test/common.h
index ef01ada426..df0ecd3aef 100644
--- a/libtiledbsoma/test/common.h
+++ b/libtiledbsoma/test/common.h
@@ -69,7 +69,6 @@ struct DimInfo {
     int64_t dim_max;
     std::string string_lo;  // For custom/restricted DataFrame domains
     std::string string_hi;  // For custom/restricted DataFrame domains
-    bool use_current_domain;
 };
 
 // E.g. "a0" is of type TILEDB_FLOAT64
diff --git a/libtiledbsoma/test/unit_soma_collection.cc b/libtiledbsoma/test/unit_soma_collection.cc
index 2e1d0a383b..5702991185 100644
--- a/libtiledbsoma/test/unit_soma_collection.cc
+++ b/libtiledbsoma/test/unit_soma_collection.cc
@@ -70,8 +70,7 @@ TEST_CASE("SOMACollection: add SOMASparseNDArray") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = DIM_MAX,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
 
         auto index_columns = helper::create_column_index_info(dim_infos);
 
@@ -127,8 +126,7 @@ TEST_CASE("SOMACollection: add SOMADenseNDArray") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = DIM_MAX,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
         auto index_columns = helper::create_column_index_info(dim_infos);
 
         std::map<std::string, SOMAGroupEntry> expected_map{
@@ -188,8 +186,7 @@ TEST_CASE("SOMACollection: add SOMADataFrame") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = DIM_MAX,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
         std::vector<helper::AttrInfo> attr_infos(
             {{.name = attr_name, .tiledb_datatype = tiledb_datatype}});
         auto [schema, index_columns] =
@@ -284,8 +281,7 @@ TEST_CASE("SOMACollection: add SOMAExperiment") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = DIM_MAX,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
         std::vector<helper::AttrInfo> attr_infos(
             {{.name = attr_name, .tiledb_datatype = tiledb_datatype}});
         auto [schema, index_columns] =
@@ -340,8 +336,7 @@ TEST_CASE("SOMACollection: add SOMAMeasurement") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = DIM_MAX,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
         std::vector<helper::AttrInfo> attr_infos(
             {{.name = attr_name, .tiledb_datatype = tiledb_datatype}});
         auto [schema, index_columns] =
@@ -455,8 +450,7 @@ TEST_CASE("SOMAExperiment: metadata") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = DIM_MAX,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
         std::vector<helper::AttrInfo> attr_infos(
             {{.name = attr_name, .tiledb_datatype = tiledb_datatype}});
         auto [schema, index_columns] =
@@ -549,8 +543,7 @@ TEST_CASE("SOMAMeasurement: metadata") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = DIM_MAX,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
         std::vector<helper::AttrInfo> attr_infos(
             {{.name = attr_name, .tiledb_datatype = tiledb_datatype}});
         auto [schema, index_columns] =
diff --git a/libtiledbsoma/test/unit_soma_dataframe.cc b/libtiledbsoma/test/unit_soma_dataframe.cc
index f8d4fb06f7..0dc9d623cb 100644
--- a/libtiledbsoma/test/unit_soma_dataframe.cc
+++ b/libtiledbsoma/test/unit_soma_dataframe.cc
@@ -75,33 +75,29 @@ struct VariouslyIndexedDataFrameFixture {
     std::string attr_1_arrow_format = ArrowAdapter::tdb_to_arrow_type(
         str_datatype);
 
-    helper::DimInfo i64_dim_info(bool use_current_domain) {
+    helper::DimInfo i64_dim_info() {
         return helper::DimInfo(
             {.name = i64_name,
              .tiledb_datatype = i64_datatype,
              .dim_max = i64_dim_max,
              .string_lo = "N/A",
-             .string_hi = "N/A",
-             .use_current_domain = use_current_domain});
+             .string_hi = "N/A"});
     }
-    helper::DimInfo u32_dim_info(bool use_current_domain) {
+    helper::DimInfo u32_dim_info() {
         return helper::DimInfo(
             {.name = u32_name,
              .tiledb_datatype = u32_datatype,
              .dim_max = u32_dim_max,
              .string_lo = "N/A",
-             .string_hi = "N/A",
-             .use_current_domain = use_current_domain});
+             .string_hi = "N/A"});
     }
-    helper::DimInfo str_dim_info(
-        bool use_current_domain, std::string string_lo, std::string string_hi) {
+    helper::DimInfo str_dim_info(std::string string_lo, std::string string_hi) {
         return helper::DimInfo(
             {.name = str_name,
              .tiledb_datatype = str_datatype,
              .dim_max = str_dim_max,
              .string_lo = string_lo,
-             .string_hi = string_hi,
-             .use_current_domain = use_current_domain});
+             .string_hi = string_hi});
     }
 
     helper::AttrInfo i64_attr_info(std::string name = i64_name) {
@@ -211,8 +207,7 @@ TEST_CASE_METHOD(
         set_up(
             std::make_shared<SOMAContext>(), "mem://unit-test-dataframe-basic");
 
-        std::vector<helper::DimInfo> dim_infos(
-            {i64_dim_info(use_current_domain)});
+        std::vector<helper::DimInfo> dim_infos({i64_dim_info()});
         std::vector<helper::AttrInfo> attr_infos({u32_attr_info()});
 
         REQUIRE(!SOMADataFrame::exists(uri_, ctx_));
@@ -325,8 +320,7 @@ TEST_CASE_METHOD(
                                         filter.first + R"(]}})";
             }
 
-            std::vector<helper::DimInfo> dim_infos(
-                {i64_dim_info(use_current_domain)});
+            std::vector<helper::DimInfo> dim_infos({i64_dim_info()});
             std::vector<helper::AttrInfo> attr_infos({i64_attr_info("a0")});
 
             REQUIRE(!SOMADataFrame::exists(uri_, ctx_));
@@ -394,8 +388,7 @@ TEST_CASE_METHOD(
     SECTION(std::format("- use_current_domain={}", use_current_domain)) {
         set_up(std::make_shared<SOMAContext>(), "mem://unit-test-collection");
 
-        std::vector<helper::DimInfo> dim_infos(
-            {i64_dim_info(use_current_domain)});
+        std::vector<helper::DimInfo> dim_infos({i64_dim_info()});
         std::vector<helper::AttrInfo> attr_infos({u32_attr_info()});
 
         REQUIRE(!SOMADataFrame::exists(uri_, ctx_));
@@ -458,13 +451,12 @@ TEST_CASE_METHOD(
     VariouslyIndexedDataFrameFixture,
     "SOMADataFrame: bounds-checking",
     "[SOMADataFrame]") {
-    bool use_current_domain = true;
     int old_max = SOMA_JOINID_DIM_MAX;
     int new_max = SOMA_JOINID_RESIZE_DIM_MAX;
 
     set_up(std::make_shared<SOMAContext>(), "mem://unit-test-bounds-checking");
 
-    std::vector<helper::DimInfo> dim_infos({i64_dim_info(use_current_domain)});
+    std::vector<helper::DimInfo> dim_infos({i64_dim_info()});
     std::vector<helper::AttrInfo> attr_infos({u32_attr_info()});
 
     REQUIRE(!SOMADataFrame::exists(uri_, ctx_));
@@ -522,8 +514,7 @@ TEST_CASE_METHOD(
                 "mem://unit-test-variant-indexed-dataframe-1-" + suffix1 + "-" +
                     suffix2);
 
-            std::vector<helper::DimInfo> dim_infos(
-                {i64_dim_info(use_current_domain)});
+            std::vector<helper::DimInfo> dim_infos({i64_dim_info()});
             std::vector<helper::AttrInfo> attr_infos(
                 {str_attr_info(), u32_attr_info()});
 
@@ -534,18 +525,14 @@ TEST_CASE_METHOD(
             auto sdf = open(OpenMode::read);
 
             CurrentDomain current_domain = sdf->get_current_domain_for_test();
-            if (!use_current_domain) {
-                REQUIRE(current_domain.is_empty());
-            } else {
-                REQUIRE(!current_domain.is_empty());
-                REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
-                NDRectangle ndrect = current_domain.ndrectangle();
+            REQUIRE(!current_domain.is_empty());
+            REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
+            NDRectangle ndrect = current_domain.ndrectangle();
 
-                std::array<int64_t, 2> i64_range = ndrect.range<int64_t>(
-                    dim_infos[0].name);
-                REQUIRE(i64_range[0] == (int64_t)0);
-                REQUIRE(i64_range[1] == (int64_t)dim_infos[0].dim_max);
-            }
+            std::array<int64_t, 2> i64_range = ndrect.range<int64_t>(
+                dim_infos[0].name);
+            REQUIRE(i64_range[0] == (int64_t)0);
+            REQUIRE(i64_range[1] == (int64_t)dim_infos[0].dim_max);
 
             // Check shape before resize
             int64_t expect = dim_infos[0].dim_max + 1;
@@ -592,11 +579,7 @@ TEST_CASE_METHOD(
 
             REQUIRE(maxdom_sjid.size() == 2);
             REQUIRE(maxdom_sjid[0] == 0);
-            if (!use_current_domain) {
-                REQUIRE(maxdom_sjid[1] == SOMA_JOINID_DIM_MAX);
-            } else {
-                REQUIRE(maxdom_sjid[1] > 2000000000);
-            }
+            REQUIRE(maxdom_sjid[1] > 2000000000);
             sdf->close();
 
             REQUIRE(sdf->nnz() == 2);
@@ -615,133 +598,85 @@ TEST_CASE_METHOD(
                 std::vector<int64_t>({0, 0}));
             auto domain_table = ArrowTable(
                 std::move(domain_array), std::move(domain_schema));
-            if (!use_current_domain) {
-                StatusAndReason check = sdf->can_upgrade_domain(
-                    domain_table, "testing");
-                REQUIRE(check.first == true);
-                REQUIRE(check.second == "");
-            } else {
-                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                    1, "testing");
-                // Must fail since this is too small.
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: dataframe already has its domain set.");
-            }
+            StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
+                1, "testing");
+            // Must fail since this is too small.
+            REQUIRE(check.first == false);
+            REQUIRE(
+                check.second ==
+                "testing: dataframe already has its domain set.");
 
             // Check can_upgrade_soma_joinid_shape
-            if (!use_current_domain) {
-                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                    1, "testing");
-                REQUIRE(check.first == true);
-                REQUIRE(check.second == "");
-            } else {
-                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                    1, "testing");
-                // Must fail since this is too small.
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: dataframe already has its domain set.");
-            }
+            check = sdf->can_upgrade_soma_joinid_shape(1, "testing");
+            // Must fail since this is too small.
+            REQUIRE(check.first == false);
+            REQUIRE(
+                check.second ==
+                "testing: dataframe already has its domain set.");
 
             sdf->close();
 
             // Resize
             auto new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
 
-            if (!use_current_domain) {
-                // Core domain is already set. The domain (not core current
-                // domain but core domain)
-                // is immutable. All we can do is check for:
-                // * throw on write beyond domain
-                // * throw on an attempt to resize.
-                REQUIRE_THROWS(
-                    write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
+            // Expect throw on write beyond current domain before resize
+            REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
-                sdf = open(OpenMode::write);
+            // Check shape after write
+            sdf = open(OpenMode::read);
+            expect = dim_infos[0].dim_max + 1;
 
-                // Array not resizeable if it has not already been sized
-                if (test_upgrade_domain) {
-                    std::unique_ptr<ArrowSchema>
-                        domain_schema = create_index_cols_info_schema(
-                            dim_infos);
-                    auto domain_array = ArrowAdapter::make_arrow_array_parent(
-                        dim_infos.size());
-                    domain_array
-                        ->children[0] = ArrowAdapter::make_arrow_array_child(
-                        std::vector<int64_t>({0, new_shape - 1}));
-                    auto domain_table = ArrowTable(
-                        std::move(domain_array), std::move(domain_schema));
-                    REQUIRE_THROWS(sdf->change_domain(domain_table, "testing"));
-                } else {
-                    REQUIRE_THROWS(
-                        sdf->resize_soma_joinid_shape(new_shape, "testing"));
-                }
+            actual = sdf->maybe_soma_joinid_shape();
+            REQUIRE(actual.has_value());
+            REQUIRE(actual.value() == expect);
+            sdf->close();
 
-            } else {
-                // Expect throw on write beyond current domain before resize
-                REQUIRE_THROWS(
-                    write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
+            // Apply the domain change
+            if (test_upgrade_domain) {
+                std::unique_ptr<ArrowSchema>
+                    domain_schema = create_index_cols_info_schema(dim_infos);
+                auto domain_array = ArrowAdapter::make_arrow_array_parent(
+                    dim_infos.size());
+                domain_array
+                    ->children[0] = ArrowAdapter::make_arrow_array_child(
+                    std::vector<int64_t>({0, new_shape - 1}));
+                auto domain_table = ArrowTable(
+                    std::move(domain_array), std::move(domain_schema));
 
-                // Check shape after write
+                // Not open for write
                 sdf = open(OpenMode::read);
-                expect = dim_infos[0].dim_max + 1;
-
-                std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
-                REQUIRE(actual.has_value());
-                REQUIRE(actual.value() == expect);
+                REQUIRE_THROWS(sdf->change_domain(domain_table, "testing"));
                 sdf->close();
 
-                // Apply the domain change
-                if (test_upgrade_domain) {
-                    std::unique_ptr<ArrowSchema>
-                        domain_schema = create_index_cols_info_schema(
-                            dim_infos);
-                    auto domain_array = ArrowAdapter::make_arrow_array_parent(
-                        dim_infos.size());
-                    domain_array
-                        ->children[0] = ArrowAdapter::make_arrow_array_child(
-                        std::vector<int64_t>({0, new_shape - 1}));
-                    auto domain_table = ArrowTable(
-                        std::move(domain_array), std::move(domain_schema));
-
-                    // Not open for write
-                    sdf = open(OpenMode::read);
-                    REQUIRE_THROWS(sdf->change_domain(domain_table, "testing"));
-                    sdf->close();
-
-                    // Open for write
-                    sdf = open(OpenMode::write);
-                    sdf->change_domain(domain_table, "testing");
-                    sdf->close();
-
-                } else {
-                    // Not open for write
-                    sdf = open(OpenMode::read);
-                    REQUIRE_THROWS(
-                        sdf->resize_soma_joinid_shape(new_shape, "testing"));
-                    sdf->close();
-
-                    // Open for write
-                    sdf = open(OpenMode::write);
-                    sdf->resize_soma_joinid_shape(new_shape, "testing");
-                    sdf->close();
-                }
+                // Open for write
+                sdf = open(OpenMode::write);
+                sdf->change_domain(domain_table, "testing");
+                sdf->close();
 
-                // Check shape after resize
+            } else {
+                // Not open for write
                 sdf = open(OpenMode::read);
-                expect = SOMA_JOINID_RESIZE_DIM_MAX + 1;
-                actual = sdf->maybe_soma_joinid_shape();
-                REQUIRE(actual.has_value());
-                REQUIRE(actual.value() == expect);
+                REQUIRE_THROWS(
+                    sdf->resize_soma_joinid_shape(new_shape, "testing"));
                 sdf->close();
 
-                // Implicitly we expect no throw
-                write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
+                // Open for write
+                sdf = open(OpenMode::write);
+                sdf->resize_soma_joinid_shape(new_shape, "testing");
+                sdf->close();
             }
 
+            // Check shape after resize
+            sdf = open(OpenMode::read);
+            expect = SOMA_JOINID_RESIZE_DIM_MAX + 1;
+            actual = sdf->maybe_soma_joinid_shape();
+            REQUIRE(actual.has_value());
+            REQUIRE(actual.value() == expect);
+            sdf->close();
+
+            // Implicitly we expect no throw
+            write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
+
             // Check domainish accessors after resize
             sdf->open(OpenMode::read);
 
@@ -757,59 +692,26 @@ TEST_CASE_METHOD(
             maxdom_sjid = ArrowAdapter::get_table_non_string_column_by_name<
                 int64_t>(soma_maxdomain, "soma_joinid");
 
-            if (!use_current_domain) {
-                REQUIRE(ned_sjid == std::vector<int64_t>({1, 10}));
-                REQUIRE(
-                    dom_sjid == std::vector<int64_t>({0, SOMA_JOINID_DIM_MAX}));
-                REQUIRE(
-                    maxdom_sjid ==
-                    std::vector<int64_t>({0, SOMA_JOINID_DIM_MAX}));
-            } else {
-                REQUIRE(ned_sjid == std::vector<int64_t>({1, 101}));
-                REQUIRE(
-                    dom_sjid ==
-                    std::vector<int64_t>({0, SOMA_JOINID_RESIZE_DIM_MAX}));
-                REQUIRE(maxdom_sjid.size() == 2);
-                REQUIRE(maxdom_sjid[0] == 0);
-                REQUIRE(maxdom_sjid[1] > 2000000000);
-            }
+            REQUIRE(ned_sjid == std::vector<int64_t>({1, 101}));
+            REQUIRE(
+                dom_sjid ==
+                std::vector<int64_t>({0, SOMA_JOINID_RESIZE_DIM_MAX}));
+            REQUIRE(maxdom_sjid.size() == 2);
+            REQUIRE(maxdom_sjid[0] == 0);
+            REQUIRE(maxdom_sjid[1] > 2000000000);
 
             // Check can_resize_soma_joinid_shape
-            StatusAndReason check = sdf->can_resize_soma_joinid_shape(
-                1, "testing");
-            if (!use_current_domain) {
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: dataframe currently has no domain set.");
-
-                REQUIRE(!sdf->has_current_domain());
-                sdf->close();
-
-                sdf = open(OpenMode::write);
-                sdf->upgrade_soma_joinid_shape(
-                    SOMA_JOINID_DIM_MAX + 1, "testing");
-                sdf->close();
-
-                sdf = open(OpenMode::read);
-                REQUIRE(sdf->has_current_domain());
-                std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
-                REQUIRE(actual.has_value());
-                REQUIRE(actual.value() == SOMA_JOINID_DIM_MAX + 1);
-                sdf->close();
-
-            } else {
-                // Must fail since this is too small.
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: new soma_joinid shape 1 < existing shape "
-                    "200");
-                check = sdf->can_resize_soma_joinid_shape(
-                    SOMA_JOINID_RESIZE_DIM_MAX + 1, "testing");
-                REQUIRE(check.first == true);
-                REQUIRE(check.second == "");
-            }
+            check = sdf->can_resize_soma_joinid_shape(1, "testing");
+            // Must fail since this is too small.
+            REQUIRE(check.first == false);
+            REQUIRE(
+                check.second ==
+                "testing: new soma_joinid shape 1 < existing shape "
+                "200");
+            check = sdf->can_resize_soma_joinid_shape(
+                SOMA_JOINID_RESIZE_DIM_MAX + 1, "testing");
+            REQUIRE(check.first == true);
+            REQUIRE(check.second == "");
 
             sdf->close();
 
@@ -863,8 +765,7 @@ TEST_CASE_METHOD(
                     suffix2);
 
             std::vector<helper::DimInfo> dim_infos(
-                {u32_dim_info(use_current_domain),
-                 i64_dim_info(use_current_domain)});
+                {u32_dim_info(), i64_dim_info()});
             std::vector<helper::AttrInfo> attr_infos({str_attr_info()});
 
             // Create
@@ -874,23 +775,19 @@ TEST_CASE_METHOD(
             auto sdf = open(OpenMode::read);
 
             CurrentDomain current_domain = sdf->get_current_domain_for_test();
-            if (!use_current_domain) {
-                REQUIRE(current_domain.is_empty());
-            } else {
-                REQUIRE(!current_domain.is_empty());
-                REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
-                NDRectangle ndrect = current_domain.ndrectangle();
+            REQUIRE(!current_domain.is_empty());
+            REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
+            NDRectangle ndrect = current_domain.ndrectangle();
 
-                std::array<uint32_t, 2> u32_range = ndrect.range<uint32_t>(
-                    dim_infos[0].name);
-                REQUIRE(u32_range[0] == (uint32_t)0);
-                REQUIRE(u32_range[1] == (uint32_t)dim_infos[0].dim_max);
+            std::array<uint32_t, 2> u32_range = ndrect.range<uint32_t>(
+                dim_infos[0].name);
+            REQUIRE(u32_range[0] == (uint32_t)0);
+            REQUIRE(u32_range[1] == (uint32_t)dim_infos[0].dim_max);
 
-                std::array<int64_t, 2> i64_range = ndrect.range<int64_t>(
-                    dim_infos[1].name);
-                REQUIRE(i64_range[0] == (int64_t)0);
-                REQUIRE(i64_range[1] == (int64_t)dim_infos[1].dim_max);
-            }
+            std::array<int64_t, 2> i64_range = ndrect.range<int64_t>(
+                dim_infos[1].name);
+            REQUIRE(i64_range[0] == (int64_t)0);
+            REQUIRE(i64_range[1] == (int64_t)dim_infos[1].dim_max);
 
             // Check shape before write
             int64_t expect = dim_infos[1].dim_max + 1;
@@ -946,11 +843,7 @@ TEST_CASE_METHOD(
             REQUIRE(maxdom_u32.size() == 2);
 
             REQUIRE(maxdom_u32[0] == 0);
-            if (!use_current_domain) {
-                REQUIRE(maxdom_u32[1] == 9999);
-            } else {
-                REQUIRE(maxdom_u32[1] > 2000000000);
-            }
+            REQUIRE(maxdom_u32[1] > 2000000000);
 
             sdf->close();
 
@@ -962,20 +855,13 @@ TEST_CASE_METHOD(
             REQUIRE(actual.value() == expect);
 
             // Check can_upgrade_soma_joinid_shape
-            if (!use_current_domain) {
-                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                    1, "testing");
-                REQUIRE(check.first == true);
-                REQUIRE(check.second == "");
-            } else {
-                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                    1, "testing");
-                // Must fail since this is too small.
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: dataframe already has its domain set.");
-            }
+            StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
+                1, "testing");
+            // Must fail since this is too small.
+            REQUIRE(check.first == false);
+            REQUIRE(
+                check.second ==
+                "testing: dataframe already has its domain set.");
 
             // Check can_upgrade_domain
             std::unique_ptr<ArrowSchema>
@@ -990,20 +876,12 @@ TEST_CASE_METHOD(
             auto domain_table = ArrowTable(
                 std::move(domain_array), std::move(domain_schema));
 
-            if (!use_current_domain) {
-                StatusAndReason check = sdf->can_upgrade_domain(
-                    domain_table, "testing");
-                REQUIRE(check.first == true);
-                REQUIRE(check.second == "");
-            } else {
-                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                    1, "testing");
-                // Must fail since this is too small.
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: dataframe already has its domain set.");
-            }
+            check = sdf->can_upgrade_soma_joinid_shape(1, "testing");
+            // Must fail since this is too small.
+            REQUIRE(check.first == false);
+            REQUIRE(
+                check.second ==
+                "testing: dataframe already has its domain set.");
 
             sdf->close();
 
@@ -1011,95 +889,58 @@ TEST_CASE_METHOD(
             auto new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
             uint32_t new_u32_dim_max = (uint32_t)u32_dim_max * 2 + 1;
 
-            if (!use_current_domain) {
-                // Domain is already set. The domain (not current domain but
-                // domain) is immutable. All we can do is check for:
-                // * throw on write beyond domain
-                // * throw on an attempt to resize.
-                REQUIRE_THROWS(
-                    write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
+            // Expect throw on write beyond current domain before resize
+            REQUIRE_THROWS(write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
-                sdf = open(OpenMode::write);
+            // Check shape after write
+            sdf = open(OpenMode::read);
+            expect = dim_infos[1].dim_max + 1;
+            actual = sdf->maybe_soma_joinid_shape();
+            REQUIRE(actual.has_value());
+            REQUIRE(actual.value() == expect);
+            sdf->close();
 
-                // Array not resizeable if it has not already been sized
-                if (test_upgrade_domain) {
-                    std::unique_ptr<ArrowSchema>
-                        domain_schema = create_index_cols_info_schema(
-                            dim_infos);
-                    auto domain_array = ArrowAdapter::make_arrow_array_parent(
-                        dim_infos.size());
-                    domain_array
-                        ->children[0] = ArrowAdapter::make_arrow_array_child(
-                        std::vector<uint32_t>({0, new_u32_dim_max}));
-                    domain_array
-                        ->children[1] = ArrowAdapter::make_arrow_array_child(
-                        std::vector<int64_t>({0, new_shape - 1}));
-                    auto domain_table = ArrowTable(
-                        std::move(domain_array), std::move(domain_schema));
-                    REQUIRE_THROWS(sdf->change_domain(domain_table, "testing"));
-                } else {
-                    REQUIRE_THROWS(
-                        sdf->resize_soma_joinid_shape(new_shape, "testing"));
-                }
+            // Apply the domain change
+            if (test_upgrade_domain) {
+                std::unique_ptr<ArrowSchema>
+                    domain_schema = create_index_cols_info_schema(dim_infos);
+                auto domain_array = ArrowAdapter::make_arrow_array_parent(
+                    dim_infos.size());
+                domain_array
+                    ->children[0] = ArrowAdapter::make_arrow_array_child(
+                    std::vector<uint32_t>({0, new_u32_dim_max}));
+                domain_array
+                    ->children[1] = ArrowAdapter::make_arrow_array_child(
+                    std::vector<int64_t>({0, new_shape - 1}));
+                auto domain_table = ArrowTable(
+                    std::move(domain_array), std::move(domain_schema));
 
+                // Not open for write
+                sdf = open(OpenMode::read);
+                REQUIRE_THROWS(sdf->change_domain(domain_table, "testing"));
                 sdf->close();
 
-            } else {
-                // Expect throw on write beyond current domain before resize
-                REQUIRE_THROWS(
-                    write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
+                // Open for write
+                sdf = open(OpenMode::write);
+                sdf->change_domain(domain_table, "testing");
+                sdf->close();
 
-                // Check shape after write
+            } else {
+                // Not open for write
                 sdf = open(OpenMode::read);
-                expect = dim_infos[1].dim_max + 1;
-                std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
-                REQUIRE(actual.has_value());
-                REQUIRE(actual.value() == expect);
+                REQUIRE_THROWS(
+                    sdf->resize_soma_joinid_shape(new_shape, "testing"));
                 sdf->close();
 
-                // Apply the domain change
-                if (test_upgrade_domain) {
-                    std::unique_ptr<ArrowSchema>
-                        domain_schema = create_index_cols_info_schema(
-                            dim_infos);
-                    auto domain_array = ArrowAdapter::make_arrow_array_parent(
-                        dim_infos.size());
-                    domain_array
-                        ->children[0] = ArrowAdapter::make_arrow_array_child(
-                        std::vector<uint32_t>({0, new_u32_dim_max}));
-                    domain_array
-                        ->children[1] = ArrowAdapter::make_arrow_array_child(
-                        std::vector<int64_t>({0, new_shape - 1}));
-                    auto domain_table = ArrowTable(
-                        std::move(domain_array), std::move(domain_schema));
-
-                    // Not open for write
-                    sdf = open(OpenMode::read);
-                    REQUIRE_THROWS(sdf->change_domain(domain_table, "testing"));
-                    sdf->close();
-
-                    // Open for write
-                    sdf = open(OpenMode::write);
-                    sdf->change_domain(domain_table, "testing");
-                    sdf->close();
-
-                } else {
-                    // Not open for write
-                    sdf = open(OpenMode::read);
-                    REQUIRE_THROWS(
-                        sdf->resize_soma_joinid_shape(new_shape, "testing"));
-                    sdf->close();
-
-                    // Open for write
-                    sdf = open(OpenMode::write);
-                    sdf->resize_soma_joinid_shape(new_shape, "testing");
-                    sdf->close();
-                }
+                // Open for write
+                sdf = open(OpenMode::write);
+                sdf->resize_soma_joinid_shape(new_shape, "testing");
                 sdf->close();
-
-                // Implicitly we expect no throw
-                write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
             }
+            sdf->close();
+
+            // Implicitly we expect no throw
+            write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
 
             // Check domainish accessors after resize
             sdf->open(OpenMode::read);
@@ -1122,56 +963,36 @@ TEST_CASE_METHOD(
             maxdom_u32 = ArrowAdapter::get_table_non_string_column_by_name<
                 uint32_t>(soma_maxdomain, "myuint32");
 
-            if (!use_current_domain) {
-                REQUIRE(ned_sjid == std::vector<int64_t>({1, 10}));
-                REQUIRE(ned_u32 == std::vector<uint32_t>({1234, 5678}));
-
-                REQUIRE(dom_sjid == std::vector<int64_t>({0, 99}));
-                REQUIRE(dom_u32 == std::vector<uint32_t>({0, 9999}));
-
-                REQUIRE(maxdom_sjid == std::vector<int64_t>({0, 99}));
-                REQUIRE(maxdom_u32 == std::vector<uint32_t>({0, 9999}));
+            REQUIRE(ned_sjid == std::vector<int64_t>({1, 101}));
+            REQUIRE(ned_u32 == std::vector<uint32_t>({1234, 5678}));
 
+            REQUIRE(dom_sjid == std::vector<int64_t>({0, 199}));
+            if (test_upgrade_domain) {
+                REQUIRE(dom_u32 == std::vector<uint32_t>({0, 19999}));
             } else {
-                REQUIRE(ned_sjid == std::vector<int64_t>({1, 101}));
-                REQUIRE(ned_u32 == std::vector<uint32_t>({1234, 5678}));
-
-                REQUIRE(dom_sjid == std::vector<int64_t>({0, 199}));
-                if (test_upgrade_domain) {
-                    REQUIRE(dom_u32 == std::vector<uint32_t>({0, 19999}));
-                } else {
-                    REQUIRE(dom_u32 == std::vector<uint32_t>({0, 9999}));
-                }
+                REQUIRE(dom_u32 == std::vector<uint32_t>({0, 9999}));
+            }
 
-                REQUIRE(maxdom_sjid.size() == 2);
-                REQUIRE(maxdom_sjid[0] == 0);
-                REQUIRE(maxdom_sjid[1] > 2000000000);
+            REQUIRE(maxdom_sjid.size() == 2);
+            REQUIRE(maxdom_sjid[0] == 0);
+            REQUIRE(maxdom_sjid[1] > 2000000000);
 
-                REQUIRE(maxdom_u32.size() == 2);
-                REQUIRE(maxdom_u32[0] == 0);
-                REQUIRE(maxdom_u32[1] > 2000000000);
-            }
+            REQUIRE(maxdom_u32.size() == 2);
+            REQUIRE(maxdom_u32[0] == 0);
+            REQUIRE(maxdom_u32[1] > 2000000000);
 
             // Check can_resize_soma_joinid_shape
-            StatusAndReason check = sdf->can_resize_soma_joinid_shape(
-                1, "testing");
-            if (!use_current_domain) {
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: dataframe currently has no domain set.");
-            } else {
-                // Must fail since this is too small.
-                REQUIRE(check.first == false);
-                REQUIRE(
-                    check.second ==
-                    "testing: new soma_joinid shape 1 < existing shape "
-                    "200");
-                check = sdf->can_resize_soma_joinid_shape(
-                    SOMA_JOINID_RESIZE_DIM_MAX + 1, "testing");
-                REQUIRE(check.first == true);
-                REQUIRE(check.second == "");
-            }
+            check = sdf->can_resize_soma_joinid_shape(1, "testing");
+            // Must fail since this is too small.
+            REQUIRE(check.first == false);
+            REQUIRE(
+                check.second ==
+                "testing: new soma_joinid shape 1 < existing shape "
+                "200");
+            check = sdf->can_resize_soma_joinid_shape(
+                SOMA_JOINID_RESIZE_DIM_MAX + 1, "testing");
+            REQUIRE(check.first == true);
+            REQUIRE(check.second == "");
 
             sdf->close();
         }
@@ -1205,8 +1026,7 @@ TEST_CASE_METHOD(
                 std::string string_lo = specify_domain ? "apple" : "";
                 std::string string_hi = specify_domain ? "zebra" : "";
                 std::vector<helper::DimInfo> dim_infos(
-                    {i64_dim_info(use_current_domain),
-                     str_dim_info(use_current_domain, string_lo, string_hi)});
+                    {i64_dim_info(), str_dim_info(string_lo, string_hi)});
                 std::vector<helper::AttrInfo> attr_infos({u32_attr_info()});
 
                 // Create
@@ -1217,32 +1037,27 @@ TEST_CASE_METHOD(
 
                 CurrentDomain
                     current_domain = sdf->get_current_domain_for_test();
-                if (!use_current_domain) {
-                    REQUIRE(current_domain.is_empty());
+                REQUIRE(!current_domain.is_empty());
+                REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
+                NDRectangle ndrect = current_domain.ndrectangle();
+
+                std::array<int64_t, 2> i64_range = ndrect.range<int64_t>(
+                    dim_infos[0].name);
+                REQUIRE(i64_range[0] == (int64_t)0);
+                REQUIRE(i64_range[1] == (int64_t)dim_infos[0].dim_max);
+
+                std::array<std::string, 2>
+                    str_range = ndrect.range<std::string>(dim_infos[1].name);
+                if (specify_domain) {
+                    REQUIRE(str_range[0] == dim_infos[1].string_lo);
+                    REQUIRE(str_range[1] == dim_infos[1].string_hi);
                 } else {
-                    REQUIRE(!current_domain.is_empty());
-                    REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
-                    NDRectangle ndrect = current_domain.ndrectangle();
-
-                    std::array<int64_t, 2> i64_range = ndrect.range<int64_t>(
-                        dim_infos[0].name);
-                    REQUIRE(i64_range[0] == (int64_t)0);
-                    REQUIRE(i64_range[1] == (int64_t)dim_infos[0].dim_max);
-
-                    std::array<std::string, 2>
-                        str_range = ndrect.range<std::string>(
-                            dim_infos[1].name);
-                    if (specify_domain) {
-                        REQUIRE(str_range[0] == dim_infos[1].string_lo);
-                        REQUIRE(str_range[1] == dim_infos[1].string_hi);
-                    } else {
-                        // Can we write empty strings in this range?
-                        REQUIRE(str_range[0] <= "");
-                        REQUIRE(str_range[1] >= "");
-                        // Can we write ASCII values in this range?
-                        REQUIRE(str_range[0] < " ");
-                        REQUIRE(str_range[1] > "~");
-                    }
+                    // Can we write empty strings in this range?
+                    REQUIRE(str_range[0] <= "");
+                    REQUIRE(str_range[1] >= "");
+                    // Can we write ASCII values in this range?
+                    REQUIRE(str_range[0] < " ");
+                    REQUIRE(str_range[1] > "~");
                 }
 
                 // Check shape before write
@@ -1262,7 +1077,7 @@ TEST_CASE_METHOD(
                 REQUIRE(sdf->nnz() == 4);
 
                 // Check shape after write
-                sdf = open(OpenMode::read);
+                sdf->open(OpenMode::read);
                 expect = dim_infos[0].dim_max + 1;
                 actual = sdf->maybe_soma_joinid_shape();
                 REQUIRE(actual.has_value());
@@ -1295,29 +1110,24 @@ TEST_CASE_METHOD(
 
                 REQUIRE(ned_sjid == std::vector<int64_t>({1, 10}));
                 REQUIRE(ned_str == std::vector<std::string>({"apple", "bat"}));
-
                 REQUIRE(dom_sjid == std::vector<int64_t>({0, 99}));
 
-                if (!use_current_domain) {
-                    REQUIRE(maxdom_sjid == std::vector<int64_t>({0, 99}));
+                if (specify_domain) {
+                    REQUIRE(dom_str[0] == dim_infos[1].string_lo);
+                    REQUIRE(dom_str[1] == dim_infos[1].string_hi);
                 } else {
-                    if (specify_domain) {
-                        REQUIRE(dom_str[0] == dim_infos[1].string_lo);
-                        REQUIRE(dom_str[1] == dim_infos[1].string_hi);
-                    } else {
-                        REQUIRE(dom_str[0] == "");
-                        REQUIRE(dom_str[1] == "");
-                    }
-
-                    REQUIRE(maxdom_sjid[0] == 0);
-                    REQUIRE(maxdom_sjid[1] > 2000000000);
+                    REQUIRE(dom_str[0] == "");
+                    REQUIRE(dom_str[1] == "");
                 }
+
+                REQUIRE(maxdom_sjid[0] == 0);
+                REQUIRE(maxdom_sjid[1] > 2000000000);
                 REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
 
                 sdf->close();
 
                 // Check can_upgrade_domain
-                sdf = open(OpenMode::read);
+                sdf->open(OpenMode::read);
                 std::unique_ptr<ArrowSchema>
                     domain_schema = create_index_cols_info_schema(dim_infos);
                 auto domain_array = ArrowAdapter::make_arrow_array_parent(
@@ -1330,130 +1140,77 @@ TEST_CASE_METHOD(
                     std::vector<std::string>({"a", "z"}));
                 auto domain_table = ArrowTable(
                     std::move(domain_array), std::move(domain_schema));
-                if (!use_current_domain) {
-                    StatusAndReason check = sdf->can_upgrade_domain(
-                        domain_table, "testing");
-                    REQUIRE(check.first == false);
-                    REQUIRE(
-                        check.second ==
-                        "testing for mystring: domain cannot be set for string "
-                        "index columns: please use (\"\", \"\")");
-                } else {
-                    StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                        1, "testing");
-                    // Must fail since this is too small.
-                    REQUIRE(check.first == false);
-                    REQUIRE(
-                        check.second ==
-                        "testing: dataframe already has its domain set.");
-                }
+
+                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
+                    1, "testing");
+                // Must fail since this is too small.
+                REQUIRE(check.first == false);
+                REQUIRE(
+                    check.second ==
+                    "testing: dataframe already has its domain set.");
+
                 sdf->close();
 
                 // Resize
 
                 auto new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
 
-                if (!use_current_domain) {
-                    // Domain is already set. The domain (not current domain
-                    // but domain) is immutable. All we can do is check for:
-                    // * throw on write beyond domain
-                    // * throw on an attempt to resize.
-                    REQUIRE_THROWS(
-                        write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
+                // Expect throw on write beyond current domain before
+                // resize
+                REQUIRE_THROWS(
+                    write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
 
-                    sdf = open(OpenMode::write);
+                // Check shape after write
+                sdf->open(OpenMode::read);
+                expect = dim_infos[0].dim_max + 1;
+                actual = sdf->maybe_soma_joinid_shape();
+                REQUIRE(actual.has_value());
+                REQUIRE(actual.value() == expect);
+                sdf->close();
 
-                    // Array not resizeable if it has not already been sized
-                    if (test_upgrade_domain) {
-                        std::unique_ptr<ArrowSchema>
-                            domain_schema = create_index_cols_info_schema(
-                                dim_infos);
-                        auto domain_array =
-                            ArrowAdapter::make_arrow_array_parent(
-                                dim_infos.size());
-                        domain_array->children[0] =
-                            ArrowAdapter::make_arrow_array_child(
-                                std::vector<int64_t>({0, new_shape - 1}));
-                        domain_array->children[1] =
-                            ArrowAdapter::make_arrow_array_child_string(
-                                std::vector<std::string>({"", ""}));
-                        auto domain_table = ArrowTable(
-                            std::move(domain_array), std::move(domain_schema));
-                        REQUIRE_THROWS(
-                            sdf->change_domain(domain_table, "testing"));
-                    } else {
-                        REQUIRE_THROWS(sdf->resize_soma_joinid_shape(
-                            new_shape, "testing"));
-                    }
+                // Apply the domain change
+                if (test_upgrade_domain) {
+                    std::unique_ptr<ArrowSchema>
+                        domain_schema = create_index_cols_info_schema(
+                            dim_infos);
+                    auto domain_array = ArrowAdapter::make_arrow_array_parent(
+                        dim_infos.size());
+                    domain_array
+                        ->children[0] = ArrowAdapter::make_arrow_array_child(
+                        std::vector<int64_t>({0, new_shape - 1}));
+                    domain_array->children[1] =
+                        ArrowAdapter::make_arrow_array_child_string(
+                            std::vector<std::string>({"", ""}));
+                    auto domain_table = ArrowTable(
+                        std::move(domain_array), std::move(domain_schema));
 
+                    // Not open for write
+                    sdf->open(OpenMode::read);
+                    REQUIRE_THROWS(sdf->change_domain(domain_table, "testing"));
+                    sdf->close();
+
+                    // Open for write
+                    sdf->open(OpenMode::write);
+                    sdf->change_domain(domain_table, "testing");
                     sdf->close();
 
                 } else {
-                    // Expect throw on write beyond current domain before
-                    // resize
+                    // Not open for write
+                    sdf->open(OpenMode::read);
                     REQUIRE_THROWS(
-                        write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
-
-                    // Check shape after write
-                    sdf = open(OpenMode::read);
-                    expect = dim_infos[0].dim_max + 1;
-                    std::optional<int64_t>
-                        actual = sdf->maybe_soma_joinid_shape();
-                    REQUIRE(actual.has_value());
-                    REQUIRE(actual.value() == expect);
+                        sdf->resize_soma_joinid_shape(new_shape, "testing"));
                     sdf->close();
 
-                    // Apply the domain change
-                    if (test_upgrade_domain) {
-                        std::unique_ptr<ArrowSchema>
-                            domain_schema = create_index_cols_info_schema(
-                                dim_infos);
-                        auto domain_array =
-                            ArrowAdapter::make_arrow_array_parent(
-                                dim_infos.size());
-                        domain_array->children[0] =
-                            ArrowAdapter::make_arrow_array_child(
-                                std::vector<int64_t>({0, new_shape - 1}));
-                        domain_array->children[1] =
-                            ArrowAdapter::make_arrow_array_child_string(
-                                std::vector<std::string>({"", ""}));
-                        auto domain_table = ArrowTable(
-                            std::move(domain_array), std::move(domain_schema));
-
-                        // Not open for write
-                        sdf = open(OpenMode::read);
-                        REQUIRE_THROWS(
-                            sdf->change_domain(domain_table, "testing"));
-                        sdf->close();
-
-                        // Open for write
-                        sdf = open(OpenMode::write);
-                        sdf->change_domain(domain_table, "testing");
-                        sdf->close();
-
-                    } else {
-                        // Not open for write
-                        sdf = open(OpenMode::read);
-                        REQUIRE_THROWS(sdf->resize_soma_joinid_shape(
-                            new_shape, "testing"));
-                        sdf->close();
-
-                        // Open for write
-                        sdf = open(OpenMode::write);
-                        sdf->resize_soma_joinid_shape(new_shape, "testing");
-
-                        sdf->close();
-                    }
+                    // Open for write
+                    sdf->open(OpenMode::write);
+                    sdf->resize_soma_joinid_shape(new_shape, "testing");
+
+                    sdf->close();
                 }
 
                 sdf->open(OpenMode::write);
-                if (!use_current_domain) {
-                    REQUIRE_THROWS(
-                        write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX));
-                } else {
-                    // Implicitly we expect no throw
-                    write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
-                }
+                // Implicitly we expect no throw
+                write_sjid_u32_str_data_from(SOMA_JOINID_DIM_MAX);
                 sdf->close();
 
                 // Check domainish accessors after resize
@@ -1482,45 +1239,32 @@ TEST_CASE_METHOD(
 
                 REQUIRE(dom_sjid == std::vector<int64_t>({0, 99}));
 
-                if (!use_current_domain) {
-                    REQUIRE(maxdom_sjid == std::vector<int64_t>({0, 99}));
-                    REQUIRE(dom_str == std::vector<std::string>({"", ""}));
+                if (specify_domain) {
+                    REQUIRE(dom_str[0] == dim_infos[1].string_lo);
+                    REQUIRE(dom_str[1] == dim_infos[1].string_hi);
                 } else {
-                    if (specify_domain) {
-                        REQUIRE(dom_str[0] == dim_infos[1].string_lo);
-                        REQUIRE(dom_str[1] == dim_infos[1].string_hi);
-                    } else {
-                        REQUIRE(dom_str == std::vector<std::string>({"", ""}));
-                    }
-
-                    REQUIRE(maxdom_sjid[0] == 0);
-                    REQUIRE(maxdom_sjid[1] > 2000000000);
+                    REQUIRE(dom_str == std::vector<std::string>({"", ""}));
                 }
 
+                REQUIRE(maxdom_sjid[0] == 0);
+                REQUIRE(maxdom_sjid[1] > 2000000000);
+
                 REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
 
                 REQUIRE(ned_str == std::vector<std::string>({"", ""}));
 
                 // Check can_resize_soma_joinid_shape
-                StatusAndReason check = sdf->can_resize_soma_joinid_shape(
-                    1, "testing");
-                if (!use_current_domain) {
-                    REQUIRE(check.first == false);
-                    REQUIRE(
-                        check.second ==
-                        "testing: dataframe currently has no domain set.");
-                } else {
-                    // Must fail since this is too small.
-                    REQUIRE(check.first == false);
-                    REQUIRE(
-                        check.second ==
-                        "testing: new soma_joinid shape 1 < existing shape "
-                        "100");
-                    check = sdf->can_resize_soma_joinid_shape(
-                        SOMA_JOINID_RESIZE_DIM_MAX + 1, "testing");
-                    REQUIRE(check.first == true);
-                    REQUIRE(check.second == "");
-                }
+                check = sdf->can_resize_soma_joinid_shape(1, "testing");
+                // Must fail since this is too small.
+                REQUIRE(check.first == false);
+                REQUIRE(
+                    check.second ==
+                    "testing: new soma_joinid shape 1 < existing shape "
+                    "100");
+                check = sdf->can_resize_soma_joinid_shape(
+                    SOMA_JOINID_RESIZE_DIM_MAX + 1, "testing");
+                REQUIRE(check.first == true);
+                REQUIRE(check.second == "");
 
                 sdf->close();
             }
@@ -1555,8 +1299,7 @@ TEST_CASE_METHOD(
                 std::string string_lo = specify_domain ? "apple" : "";
                 std::string string_hi = specify_domain ? "zebra" : "";
                 std::vector<helper::DimInfo> dim_infos(
-                    {str_dim_info(use_current_domain, string_lo, string_hi),
-                     u32_dim_info(use_current_domain)});
+                    {str_dim_info(string_lo, string_hi), u32_dim_info()});
                 std::vector<helper::AttrInfo> attr_infos({i64_attr_info()});
 
                 // Create
@@ -1567,34 +1310,29 @@ TEST_CASE_METHOD(
 
                 CurrentDomain
                     current_domain = sdf->get_current_domain_for_test();
-                if (!use_current_domain) {
-                    REQUIRE(current_domain.is_empty());
+                REQUIRE(!current_domain.is_empty());
+                REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
+                NDRectangle ndrect = current_domain.ndrectangle();
+
+                std::array<std::string, 2>
+                    str_range = ndrect.range<std::string>(dim_infos[0].name);
+                if (specify_domain) {
+                    REQUIRE(str_range[0] == dim_infos[0].string_lo);
+                    REQUIRE(str_range[1] == dim_infos[0].string_hi);
                 } else {
-                    REQUIRE(!current_domain.is_empty());
-                    REQUIRE(current_domain.type() == TILEDB_NDRECTANGLE);
-                    NDRectangle ndrect = current_domain.ndrectangle();
-
-                    std::array<std::string, 2>
-                        str_range = ndrect.range<std::string>(
-                            dim_infos[0].name);
-                    if (specify_domain) {
-                        REQUIRE(str_range[0] == dim_infos[0].string_lo);
-                        REQUIRE(str_range[1] == dim_infos[0].string_hi);
-                    } else {
-                        // Can we write empty strings in this range?
-                        REQUIRE(str_range[0] <= "");
-                        REQUIRE(str_range[1] >= "");
-                        // Can we write ASCII values in this range?
-                        REQUIRE(str_range[0] < " ");
-                        REQUIRE(str_range[1] > "~");
-                    }
-
-                    std::array<uint32_t, 2> u32_range = ndrect.range<uint32_t>(
-                        dim_infos[1].name);
-                    REQUIRE(u32_range[0] == (uint32_t)0);
-                    REQUIRE(u32_range[1] == (uint32_t)dim_infos[1].dim_max);
+                    // Can we write empty strings in this range?
+                    REQUIRE(str_range[0] <= "");
+                    REQUIRE(str_range[1] >= "");
+                    // Can we write ASCII values in this range?
+                    REQUIRE(str_range[0] < " ");
+                    REQUIRE(str_range[1] > "~");
                 }
 
+                std::array<uint32_t, 2> u32_range = ndrect.range<uint32_t>(
+                    dim_infos[1].name);
+                REQUIRE(u32_range[0] == (uint32_t)0);
+                REQUIRE(u32_range[1] == (uint32_t)dim_infos[1].dim_max);
+
                 // Check shape before write
                 std::optional<int64_t> actual = sdf->maybe_soma_joinid_shape();
                 REQUIRE(!actual.has_value());
@@ -1617,18 +1355,13 @@ TEST_CASE_METHOD(
 
                 REQUIRE(ned_str == std::vector<std::string>({"", ""}));
 
-                if (!use_current_domain) {
-                    REQUIRE(dom_str == std::vector<std::string>({"", ""}));
-                    REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
+                if (specify_domain) {
+                    REQUIRE(dom_str[0] == dim_infos[0].string_lo);
+                    REQUIRE(dom_str[1] == dim_infos[0].string_hi);
                 } else {
-                    if (specify_domain) {
-                        REQUIRE(dom_str[0] == dim_infos[0].string_lo);
-                        REQUIRE(dom_str[1] == dim_infos[0].string_hi);
-                    } else {
-                        REQUIRE(dom_str == std::vector<std::string>({"", ""}));
-                    }
-                    REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
+                    REQUIRE(dom_str == std::vector<std::string>({"", ""}));
                 }
+                REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
 
                 sdf->close();
 
@@ -1663,112 +1396,65 @@ TEST_CASE_METHOD(
                     std::vector<uint32_t>({0, 0}));
                 auto domain_table = ArrowTable(
                     std::move(domain_array), std::move(domain_schema));
-                if (!use_current_domain) {
-                    StatusAndReason check = sdf->can_upgrade_domain(
-                        domain_table, "testing");
-                    REQUIRE(check.first == false);
-                    REQUIRE(
-                        check.second ==
-                        "testing for mystring: domain cannot be set for string "
-                        "index columns: please use (\"\", \"\")");
-                } else {
-                    StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
-                        1, "testing");
-                    // Must fail since this is too small.
-                    REQUIRE(check.first == false);
-                    REQUIRE(
-                        check.second ==
-                        "testing: dataframe already has its domain set.");
-                }
+
+                StatusAndReason check = sdf->can_upgrade_soma_joinid_shape(
+                    1, "testing");
+                // Must fail since this is too small.
+                REQUIRE(check.first == false);
+                REQUIRE(
+                    check.second ==
+                    "testing: dataframe already has its domain set.");
+
                 sdf->close();
 
                 // Resize
                 int64_t new_shape = int64_t{SOMA_JOINID_RESIZE_DIM_MAX + 1};
                 uint32_t new_u32_dim_max = u32_dim_max * 2 + 1;
 
-                if (!use_current_domain) {
-                    // Domain is already set. The domain (not current domain
-                    // but domain) is immutable. All we can do is check for:
-                    // * throw on write beyond domain -- except here,
-                    // soma_joinid is not
-                    //   a dim, so no throw
-                    // * throw on an attempt to resize.
+                // Check shape after write
+                sdf = open(OpenMode::read);
+                actual = sdf->maybe_soma_joinid_shape();
+                REQUIRE(!actual.has_value());
+                sdf->close();
 
-                    sdf = open(OpenMode::write);
+                // Apply the domain change
+                if (test_upgrade_domain) {
+                    std::unique_ptr<ArrowSchema>
+                        domain_schema = create_index_cols_info_schema(
+                            dim_infos);
+                    auto domain_array = ArrowAdapter::make_arrow_array_parent(
+                        dim_infos.size());
+                    domain_array->children[0] =
+                        ArrowAdapter::make_arrow_array_child_string(
+                            std::vector<std::string>({"", ""}));
+                    domain_array
+                        ->children[1] = ArrowAdapter::make_arrow_array_child(
+                        std::vector<uint32_t>({0, new_u32_dim_max}));
+                    auto domain_table = ArrowTable(
+                        std::move(domain_array), std::move(domain_schema));
 
-                    // Array not resizeable if it has not already been sized
-                    if (test_upgrade_domain) {
-                        std::unique_ptr<ArrowSchema>
-                            domain_schema = create_index_cols_info_schema(
-                                dim_infos);
-                        auto domain_array =
-                            ArrowAdapter::make_arrow_array_parent(
-                                dim_infos.size());
-                        domain_array->children[0] =
-                            ArrowAdapter::make_arrow_array_child_string(
-                                std::vector<std::string>({"", ""}));
-                        domain_array->children[1] =
-                            ArrowAdapter::make_arrow_array_child(
-                                std::vector<uint32_t>({0, new_u32_dim_max}));
-                        auto domain_table = ArrowTable(
-                            std::move(domain_array), std::move(domain_schema));
-                        REQUIRE_THROWS(
-                            sdf->change_domain(domain_table, "testing"));
-                    } else {
-                        REQUIRE_THROWS(sdf->resize_soma_joinid_shape(
-                            new_shape, "testing"));
-                    }
+                    // Not open for write
+                    sdf = open(OpenMode::read);
+                    // REQUIRE_THROWS(sdf->change_domain(domain_table,
+                    // "testing"));
+                    sdf->close();
 
+                    // Open for write
+                    sdf = open(OpenMode::write);
+                    sdf->change_domain(domain_table, "testing");
                     sdf->close();
 
                 } else {
-                    // Check shape after write
+                    // Not open for write
                     sdf = open(OpenMode::read);
-                    std::optional<int64_t>
-                        actual = sdf->maybe_soma_joinid_shape();
-                    REQUIRE(!actual.has_value());
+                    REQUIRE_THROWS(
+                        sdf->resize_soma_joinid_shape(new_shape, "testing"));
                     sdf->close();
 
-                    // Apply the domain change
-                    if (test_upgrade_domain) {
-                        std::unique_ptr<ArrowSchema>
-                            domain_schema = create_index_cols_info_schema(
-                                dim_infos);
-                        auto domain_array =
-                            ArrowAdapter::make_arrow_array_parent(
-                                dim_infos.size());
-                        domain_array->children[0] =
-                            ArrowAdapter::make_arrow_array_child_string(
-                                std::vector<std::string>({"", ""}));
-                        domain_array->children[1] =
-                            ArrowAdapter::make_arrow_array_child(
-                                std::vector<uint32_t>({0, new_u32_dim_max}));
-                        auto domain_table = ArrowTable(
-                            std::move(domain_array), std::move(domain_schema));
-
-                        // Not open for write
-                        sdf = open(OpenMode::read);
-                        REQUIRE_THROWS(
-                            sdf->change_domain(domain_table, "testing"));
-                        sdf->close();
-
-                        // Open for write
-                        sdf = open(OpenMode::write);
-                        sdf->change_domain(domain_table, "testing");
-                        sdf->close();
-
-                    } else {
-                        // Not open for write
-                        sdf = open(OpenMode::read);
-                        REQUIRE_THROWS(sdf->resize_soma_joinid_shape(
-                            new_shape, "testing"));
-                        sdf->close();
-
-                        // Open for write
-                        sdf = open(OpenMode::write);
-                        sdf->resize_soma_joinid_shape(new_shape, "testing");
-                        sdf->close();
-                    }
+                    // Open for write
+                    sdf = open(OpenMode::write);
+                    sdf->resize_soma_joinid_shape(new_shape, "testing");
+                    sdf->close();
                 }
 
                 sdf = open(OpenMode::write);
@@ -1792,32 +1478,20 @@ TEST_CASE_METHOD(
 
                 REQUIRE(ned_str == std::vector<std::string>({"", ""}));
 
-                if (!use_current_domain) {
-                    REQUIRE(dom_str == std::vector<std::string>({"", ""}));
-                    REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
+                if (specify_domain) {
+                    REQUIRE(dom_str[0] == dim_infos[0].string_lo);
+                    REQUIRE(dom_str[1] == dim_infos[0].string_hi);
                 } else {
-                    if (specify_domain) {
-                        REQUIRE(dom_str[0] == dim_infos[0].string_lo);
-                        REQUIRE(dom_str[1] == dim_infos[0].string_hi);
-                    } else {
-                        REQUIRE(dom_str == std::vector<std::string>({"", ""}));
-                    }
-                    REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
+                    REQUIRE(dom_str == std::vector<std::string>({"", ""}));
                 }
+                REQUIRE(maxdom_str == std::vector<std::string>({"", ""}));
 
                 // Check can_resize_soma_joinid_shape
-                StatusAndReason check = sdf->can_resize_soma_joinid_shape(
-                    0, "testing");
-                if (!use_current_domain) {
-                    REQUIRE(check.first == false);
-                    REQUIRE(
-                        check.second ==
-                        "testing: dataframe currently has no domain set.");
-                } else {
-                    // Must pass since soma_joinid isn't a dim in this case.
-                    REQUIRE(check.first == true);
-                    REQUIRE(check.second == "");
-                }
+                check = sdf->can_resize_soma_joinid_shape(0, "testing");
+
+                // Must pass since soma_joinid isn't a dim in this case.
+                REQUIRE(check.first == true);
+                REQUIRE(check.second == "");
 
                 sdf->close();
             }
diff --git a/libtiledbsoma/test/unit_soma_dense_ndarray.cc b/libtiledbsoma/test/unit_soma_dense_ndarray.cc
index 222b760ad1..5c8ff9c1fa 100644
--- a/libtiledbsoma/test/unit_soma_dense_ndarray.cc
+++ b/libtiledbsoma/test/unit_soma_dense_ndarray.cc
@@ -60,41 +60,14 @@ TEST_CASE("SOMADenseNDArray: basic", "[SOMADenseNDArray]") {
               .tiledb_datatype = dim_tiledb_datatype,
               .dim_max = dim_max,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
 
         auto index_columns = helper::create_column_index_info(dim_infos);
 
-        if (use_current_domain) {
-            if (helper::have_dense_current_domain_support()) {
-                SOMADenseNDArray::create(
-                    uri,
-                    dim_arrow_format,
-                    ArrowTable(
-                        std::move(index_columns.first),
-                        std::move(index_columns.second)),
-                    ctx,
-                    PlatformConfig(),
-                    TimestampRange(0, 2));
-
-                auto dnda = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
-                REQUIRE(dnda->shape() == std::vector<int64_t>{dim_max + 1});
-                dnda->close();
-            } else {
-                REQUIRE_THROWS(SOMADenseNDArray::create(
-                    uri,
-                    dim_arrow_format,
-                    ArrowTable(
-                        std::move(index_columns.first),
-                        std::move(index_columns.second)),
-                    ctx,
-                    PlatformConfig(),
-                    TimestampRange(0, 2)));
-            }
-        } else {
+        if (helper::have_dense_current_domain_support()) {
             SOMADenseNDArray::create(
                 uri,
-                attr_arrow_format,
+                dim_arrow_format,
                 ArrowTable(
                     std::move(index_columns.first),
                     std::move(index_columns.second)),
@@ -102,52 +75,19 @@ TEST_CASE("SOMADenseNDArray: basic", "[SOMADenseNDArray]") {
                 PlatformConfig(),
                 TimestampRange(0, 2));
 
-            REQUIRE(SOMADenseNDArray::exists(uri, ctx));
-            REQUIRE(!SOMADataFrame::exists(uri, ctx));
-            REQUIRE(!SOMASparseNDArray::exists(uri, ctx));
-
             auto dnda = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
-            REQUIRE(dnda->uri() == uri);
-            REQUIRE(dnda->ctx() == ctx);
-            REQUIRE(dnda->type() == "SOMADenseNDArray");
-            REQUIRE(dnda->is_sparse() == false);
-            REQUIRE(dnda->soma_data_type() == attr_arrow_format);
-            auto schema = dnda->tiledb_schema();
-            REQUIRE(schema->has_attribute("soma_data"));
-            REQUIRE(schema->array_type() == TILEDB_DENSE);
-            REQUIRE(schema->domain().has_dimension(dim_name));
-            REQUIRE(dnda->ndim() == 1);
-
-            REQUIRE(dnda->maxshape() == std::vector<int64_t>{shape});
-
-            dnda->close();
-
-            std::vector<int64_t> d0{1, 10};
-            std::vector<int32_t> a0(10, 1);
-
-            dnda->open(OpenMode::write);
-            dnda->set_column_data("soma_data", a0.size(), a0.data());
-            dnda->set_column_data(dim_name, d0.size(), d0.data());
-            dnda->write();
-            dnda->close();
-
-            dnda->open(OpenMode::read);
-            while (auto batch = dnda->read_next()) {
-                auto arrbuf = batch.value();
-                auto a0span = arrbuf->at("soma_data")->data<int32_t>();
-                REQUIRE(
-                    a0 == std::vector<int32_t>(a0span.begin(), a0span.end()));
-            }
-            dnda->close();
-
-            dnda = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
-            auto new_shape = std::vector<int64_t>({shape * 2});
-            // * When use_current_domain is false: can't resize what has not
-            //   been sized.
-            // * When use_current_domain is true: TODO: current domain not
-            //   supported for dense arrays yet (see above).
-            REQUIRE_THROWS(dnda->resize(new_shape, "testing"));
+            REQUIRE(dnda->shape() == std::vector<int64_t>{dim_max + 1});
             dnda->close();
+        } else {
+            REQUIRE_THROWS(SOMADenseNDArray::create(
+                uri,
+                dim_arrow_format,
+                ArrowTable(
+                    std::move(index_columns.first),
+                    std::move(index_columns.second)),
+                ctx,
+                PlatformConfig(),
+                TimestampRange(0, 2)));
         }
     }
 }
@@ -172,47 +112,11 @@ TEST_CASE("SOMADenseNDArray: platform_config", "[SOMADenseNDArray]") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = dim_max,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
 
         auto index_columns = helper::create_column_index_info(dim_infos);
 
-        if (use_current_domain) {
-            if (helper::have_dense_current_domain_support()) {
-                SOMADenseNDArray::create(
-                    uri,
-                    arrow_format,
-                    ArrowTable(
-                        std::move(index_columns.first),
-                        std::move(index_columns.second)),
-                    ctx,
-                    platform_config);
-
-                auto dnda = SOMADenseNDArray::open(uri, OpenMode::read, ctx);
-                auto dim_filter = dnda->tiledb_schema()
-                                      ->domain()
-                                      .dimension(dim_name)
-                                      .filter_list()
-                                      .filter(0);
-                REQUIRE(dim_filter.filter_type() == TILEDB_FILTER_ZSTD);
-                REQUIRE(
-                    dim_filter.get_option<int32_t>(TILEDB_COMPRESSION_LEVEL) ==
-                    6);
-
-                dnda->close();
-
-            } else {
-                REQUIRE_THROWS(SOMADenseNDArray::create(
-                    uri,
-                    arrow_format,
-                    ArrowTable(
-                        std::move(index_columns.first),
-                        std::move(index_columns.second)),
-                    ctx,
-                    platform_config));
-            }
-
-        } else {
+        if (helper::have_dense_current_domain_support()) {
             SOMADenseNDArray::create(
                 uri,
                 arrow_format,
@@ -233,6 +137,16 @@ TEST_CASE("SOMADenseNDArray: platform_config", "[SOMADenseNDArray]") {
                 dim_filter.get_option<int32_t>(TILEDB_COMPRESSION_LEVEL) == 6);
 
             dnda->close();
+
+        } else {
+            REQUIRE_THROWS(SOMADenseNDArray::create(
+                uri,
+                arrow_format,
+                ArrowTable(
+                    std::move(index_columns.first),
+                    std::move(index_columns.second)),
+                ctx,
+                platform_config));
         }
     }
 }
@@ -254,8 +168,7 @@ TEST_CASE("SOMADenseNDArray: metadata", "[SOMADenseNDArray]") {
               .tiledb_datatype = tiledb_datatype,
               .dim_max = dim_max,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
 
         auto index_columns = helper::create_column_index_info(dim_infos);
 
diff --git a/libtiledbsoma/test/unit_soma_geometry_dataframe.cc b/libtiledbsoma/test/unit_soma_geometry_dataframe.cc
index ff8aac67fc..e2b73d4a45 100644
--- a/libtiledbsoma/test/unit_soma_geometry_dataframe.cc
+++ b/libtiledbsoma/test/unit_soma_geometry_dataframe.cc
@@ -53,15 +53,13 @@ TEST_CASE("SOMAGeometryDataFrame: basic", "[SOMAGeometryDataFrame]") {
                   .tiledb_datatype = TILEDB_INT64,
                   .dim_max = SOMA_JOINID_DIM_MAX,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain}),
+                  .string_hi = "N/A"}),
              helper::DimInfo(
                  {.name = "soma_geometry",
                   .tiledb_datatype = TILEDB_GEOM_WKB,
                   .dim_max = 100,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain})});
+                  .string_hi = "N/A"})});
 
         std::vector<helper::DimInfo> spatial_dim_infos(
             {helper::DimInfo(
@@ -69,15 +67,13 @@ TEST_CASE("SOMAGeometryDataFrame: basic", "[SOMAGeometryDataFrame]") {
                   .tiledb_datatype = TILEDB_FLOAT64,
                   .dim_max = 200,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain}),
+                  .string_hi = "N/A"}),
              helper::DimInfo(
                  {.name = "y",
                   .tiledb_datatype = TILEDB_FLOAT64,
                   .dim_max = 100,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain})});
+                  .string_hi = "N/A"})});
 
         std::vector<helper::AttrInfo> attr_infos({helper::AttrInfo(
             {.name = "quality", .tiledb_datatype = TILEDB_FLOAT64})});
@@ -164,15 +160,13 @@ TEST_CASE("SOMAGeometryDataFrame: Roundtrip", "[SOMAGeometryDataFrame]") {
                   .tiledb_datatype = TILEDB_INT64,
                   .dim_max = SOMA_JOINID_DIM_MAX,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain}),
+                  .string_hi = "N/A"}),
              helper::DimInfo(
                  {.name = "soma_geometry",
                   .tiledb_datatype = TILEDB_GEOM_WKB,
                   .dim_max = 100,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain})});
+                  .string_hi = "N/A"})});
 
         std::vector<helper::DimInfo> spatial_dim_infos(
             {helper::DimInfo(
@@ -180,15 +174,13 @@ TEST_CASE("SOMAGeometryDataFrame: Roundtrip", "[SOMAGeometryDataFrame]") {
                   .tiledb_datatype = TILEDB_FLOAT64,
                   .dim_max = 200,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain}),
+                  .string_hi = "N/A"}),
              helper::DimInfo(
                  {.name = "y",
                   .tiledb_datatype = TILEDB_FLOAT64,
                   .dim_max = 100,
                   .string_lo = "N/A",
-                  .string_hi = "N/A",
-                  .use_current_domain = use_current_domain})});
+                  .string_hi = "N/A"})});
 
         std::vector<helper::AttrInfo> attr_infos({helper::AttrInfo(
             {.name = "quality", .tiledb_datatype = TILEDB_FLOAT64})});
diff --git a/libtiledbsoma/test/unit_soma_point_cloud_dataframe.cc b/libtiledbsoma/test/unit_soma_point_cloud_dataframe.cc
index abcf46415d..8b03620f07 100644
--- a/libtiledbsoma/test/unit_soma_point_cloud_dataframe.cc
+++ b/libtiledbsoma/test/unit_soma_point_cloud_dataframe.cc
@@ -49,22 +49,19 @@ TEST_CASE("SOMAPointCloudDataFrame: basic", "[SOMAPointCloudDataFrame]") {
                  .tiledb_datatype = TILEDB_INT64,
                  .dim_max = SOMA_JOINID_DIM_MAX,
                  .string_lo = "N/A",
-                 .string_hi = "N/A",
-                 .use_current_domain = use_current_domain}),
+                 .string_hi = "N/A"}),
             helper::DimInfo(
                 {.name = "x",
                  .tiledb_datatype = TILEDB_UINT32,
                  .dim_max = 100,
                  .string_lo = "N/A",
-                 .string_hi = "N/A",
-                 .use_current_domain = use_current_domain}),
+                 .string_hi = "N/A"}),
             helper::DimInfo(
                 {.name = "y",
                  .tiledb_datatype = TILEDB_UINT32,
                  .dim_max = 100,
                  .string_lo = "N/A",
-                 .string_hi = "N/A",
-                 .use_current_domain = use_current_domain}),
+                 .string_hi = "N/A"}),
         });
 
         std::vector<helper::AttrInfo> attr_infos({helper::AttrInfo(
diff --git a/libtiledbsoma/test/unit_soma_sparse_ndarray.cc b/libtiledbsoma/test/unit_soma_sparse_ndarray.cc
index ee468ab578..fa857add8e 100644
--- a/libtiledbsoma/test/unit_soma_sparse_ndarray.cc
+++ b/libtiledbsoma/test/unit_soma_sparse_ndarray.cc
@@ -61,8 +61,7 @@ TEST_CASE("SOMASparseNDArray: basic", "[SOMASparseNDArray]") {
               .tiledb_datatype = dim_tiledb_datatype,
               .dim_max = dim_max,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
 
         auto index_columns = helper::create_column_index_info(dim_infos);
 
@@ -95,9 +94,6 @@ TEST_CASE("SOMASparseNDArray: basic", "[SOMASparseNDArray]") {
 
         auto expect = std::vector<int64_t>({shape});
         REQUIRE(snda->shape() == expect);
-        if (!use_current_domain) {
-            REQUIRE(snda->maxshape() == expect);
-        }
 
         snda->close();
 
@@ -136,54 +132,26 @@ TEST_CASE("SOMASparseNDArray: basic", "[SOMASparseNDArray]") {
         REQUIRE_THROWS(snda->write());
         snda->close();
 
-        if (!use_current_domain) {
-            auto new_shape = std::vector<int64_t>({shape});
-
-            snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
-            // Without current-domain support: this should throw since
-            // one cannot resize what has not been sized.
-            REQUIRE(!snda->has_current_domain());
-            REQUIRE_THROWS(snda->resize(new_shape, "testing"));
-            // Now set the shape
-            snda->upgrade_shape(new_shape, "testing");
-            snda->close();
-
-            snda->open(OpenMode::read);
-            REQUIRE(snda->has_current_domain());
-            snda->close();
-
-            snda->open(OpenMode::write);
-            REQUIRE(snda->has_current_domain());
-            // Should not fail since we're setting it to what it already is.
-            snda->resize(new_shape, "testing");
-            snda->close();
-
-            snda->open(OpenMode::read);
-            REQUIRE(snda->shape() == new_shape);
-            snda->close();
-
-        } else {
-            auto new_shape = std::vector<int64_t>({shape * 2});
-
-            snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
-            // Should throw since this already has a shape (core current
-            // domain).
-            REQUIRE_THROWS(snda->upgrade_shape(new_shape, "testing"));
-            snda->resize(new_shape, "testing");
-            snda->close();
-
-            // Try out-of-bounds write after resize.
-            snda->open(OpenMode::write);
-            snda->set_column_data(dim_name, d0b.size(), d0b.data());
-            snda->set_column_data(attr_name, a0b.size(), a0b.data());
-            // Implicitly checking for no throw
-            snda->write();
-            snda->close();
-
-            snda->open(OpenMode::read);
-            REQUIRE(snda->shape() == new_shape);
-            snda->close();
-        }
+        auto new_shape = std::vector<int64_t>({shape * 2});
+
+        snda = SOMASparseNDArray::open(uri, OpenMode::write, ctx);
+        // Should throw since this already has a shape (core current
+        // domain).
+        REQUIRE_THROWS(snda->upgrade_shape(new_shape, "testing"));
+        snda->resize(new_shape, "testing");
+        snda->close();
+
+        // Try out-of-bounds write after resize.
+        snda->open(OpenMode::write);
+        snda->set_column_data(dim_name, d0b.size(), d0b.data());
+        snda->set_column_data(attr_name, a0b.size(), a0b.data());
+        // Implicitly checking for no throw
+        snda->write();
+        snda->close();
+
+        snda->open(OpenMode::read);
+        REQUIRE(snda->shape() == new_shape);
+        snda->close();
     }
 }
 
@@ -210,8 +178,7 @@ TEST_CASE("SOMASparseNDArray: platform_config", "[SOMASparseNDArray]") {
               .tiledb_datatype = dim_tiledb_datatype,
               .dim_max = dim_max,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
 
         auto index_columns = helper::create_column_index_info(dim_infos);
 
@@ -258,8 +225,7 @@ TEST_CASE("SOMASparseNDArray: metadata", "[SOMASparseNDArray]") {
               .tiledb_datatype = dim_tiledb_datatype,
               .dim_max = dim_max,
               .string_lo = "N/A",
-              .string_hi = "N/A",
-              .use_current_domain = use_current_domain}});
+              .string_hi = "N/A"}});
 
         auto index_columns = helper::create_column_index_info(dim_infos);
 
@@ -350,8 +316,7 @@ TEST_CASE(
           .tiledb_datatype = dim_tiledb_datatype,
           .dim_max = dim_max,
           .string_lo = "N/A",
-          .string_hi = "N/A",
-          .use_current_domain = true}});
+          .string_hi = "N/A"}});
 
     auto index_columns = helper::create_column_index_info(dim_infos);
 
@@ -412,8 +377,7 @@ TEST_CASE("SOMASparseNDArray: can_resize", "[SOMASparseNDArray]") {
           .tiledb_datatype = dim_tiledb_datatype,
           .dim_max = dim_max,
           .string_lo = "N/A",
-          .string_hi = "N/A",
-          .use_current_domain = true}});
+          .string_hi = "N/A"}});
 
     auto index_columns = helper::create_column_index_info(dim_infos);