# SignalR DataSource — Known Issues

Issues specific to `AcSignalRDataSource` (state management, change tracking, public API surface). Issues affecting the underlying SignalR transport itself live in `../SIGNALR/SIGNALR_ISSUES.md` (`SIG` topic).

Cross-cutting transport+DataSource concerns intentionally remain under `SIG` — see `../SIGNALR/SIGNALR_ISSUES.md#accore-sig-i-t7s2` (GetAll raw byte[] for populate/merge).

---

## ACCORE-SIGDS-B-T4K9: SaveChangesAsync silently drops per-item save Tasks

**Status:** Open
**Affects:** `AcSignalRDataSource.SaveTrackingItemUnsafeAsync` (line 1001-1002)

```csharp
private async Task SaveTrackingItemUnsafeAsync(TrackingItem<TDataItem, TId> trackingItem)
    => SaveItemUnsafeAsync(trackingItem.CurrentValue, trackingItem.TrackingState);
```

`async Task` with an expression body that produces another `Task` discards the inner Task — the outer state machine wraps a void completion, so the per-item save is fire-and-forget. The caller in `SaveChangesAsync` (line 950) `await SaveTrackingItemUnsafeAsync(trackingItem)` returns immediately; the foreach proceeds to the next item without waiting for the previous server response.

If this is the intended fire-and-forget batch behaviour, the method should drop `async` and return the inner Task explicitly (consumers can opt into await). If sequential save was the intent, the body needs `await SaveItemUnsafeAsync(...)`.

**Possible fix direction:**
```csharp
// Option A — explicit fire-and-forget (rename + drop async):
private void DispatchTrackingItemUnsafeAsync(TrackingItem<TDataItem, TId> ti)
    => SaveItemUnsafeAsync(ti.CurrentValue, ti.TrackingState).Forget();

// Option B — sequential (proper await):
private Task SaveTrackingItemUnsafeAsync(TrackingItem<TDataItem, TId> ti)
    => SaveItemUnsafeAsync(ti.CurrentValue, ti.TrackingState);
// (drop `async`; caller `await` waits the inner Task)
```

---

## ACCORE-SIGDS-I-H3M8: DataSource mutations and events run on background threads (WASM-safe; theoretical race under Blazor Server/MAUI)

**Severity:** Minor (theoretical — no repro; current consumers are single-threaded WASM/Hybrid) · **Status:** Open · **Area:** `AcSignalRDataSource` threading model

> **Note:** documents accepted current behaviour — not scheduled for change.

### Description
The DataSource does its collection work on non-UI threads:
- **Bulk loads**: `LoadDataSourceFromResponseData` → `BeginUpdate()` → `PopulateMerge` → `EndUpdate()` runs on the
  SignalR receive pipeline; `EndUpdate` raises the collection Reset notification on that thread.
- **Per-item save confirms**: `ProcessSavedResponseItem` (thread-pool continuation via
  `ContinueWith(TaskScheduler.Default)`, or the SignalR response callback) mutates the tracked item in place
  (`CopyTo` under `lock (_syncRoot)` — no Begin/EndUpdate) and then fires `OnDataSourceItemChanged` on the same
  background thread.

Consequences for subscribers:
- `OnDataSourceLoaded` / `OnDataSourceItemChanged` / `OnSyncingStateChanged` handlers execute on the event
  thread — any UI work must be marshalled by the subscriber (e.g. `InvokeAsync`).
- On single-threaded WebAssembly (the current deployment model) there is no true parallelism — safe.
- Under Blazor Server / MAUI a theoretical race exists: a bulk-load mutation on the SignalR thread can
  interleave with a UI-thread enumeration of the same collection (any render), risking
  `InvalidOperationException` (collection modified) or an inconsistent view.

### Root cause
By design: the transport delivers responses on its own pipeline and the DataSource processes them where they
arrive; marshalling is left to subscribers (the DataSource has no UI dependency).

### Known workaround
UI-layer subscribers marshal their render/refresh work via `InvokeAsync` (already the practice). A Server/MAUI
deployment would additionally need the collection mutations themselves dispatched to the UI context — see fix direction.

### Fix direction (if ever needed)
Optional marshal delegate on the DataSource (e.g. a consumer-settable `Func<Action, Task>` dispatcher) so
loads/merges/`CopyTo` run on the consumer's UI context under Server/MAUI. Not planned while all consumers are WASM/Hybrid.

---

## ACCORE-SIGDS-I-W2H6: BinarySearch is public but throws NotImplementedException

**Status:** Open
**Affects:** `AcSignalRDataSource.BinarySearch` (lines 1179, 1184, 1185)

```csharp
public int BinarySearch(int index, int count, TDataItem item, IComparer<TDataItem>? comparer)
{
    throw new NotImplementedException($"BinarySearch");
}
public int BinarySearch(TDataItem item) => BinarySearch(0, Count, item, null);
public int BinarySearch(TDataItem item, IComparer<TDataItem>? comparer) => BinarySearch(0, Count, item, comparer);
```

All three overloads are `public` (visible via IntelliSense, callable by consumers) but throw at runtime. Sort-dependent operation — DataSource ordering is not enforced by the framework, so a meaningful implementation requires an explicit sort contract.

**Possible fix directions** (mutually exclusive):
- Implement (delegating to `InnerList.BinarySearch` if `InnerList is List<TDataItem>`; for `IAcObservableCollection` document the comparer requirement).
- Mark `[Obsolete("Not implemented")]` + change visibility to `protected internal` (keeps source compatibility, hides from external callers).
- Remove the three overloads outright and rely on consumers using `IndexOf` + manual sort if needed.
