# Team Brief — AuthBlocks: Register `ModelView`'s Missing Dependency via `ConfigureAuthServices`

**Audience:** an orchestrator (and its implementers) working **only** in the AuthBlocks repository at
`C:\Development\AuthBlocks`. You do not need, and should not assume, any knowledge of the products that
consume AuthBlocks. Everything you need is in this brief or in that one repo (plus a single new BlazorBlocks
package version — see §2, the blocking prerequisite).

**Status:** ✅ RESOLVED — shipped in `Cerebellum.BlazorBlocks.Web` 10.3.33 + `Cerebellum.AuthBlocks.Web` 10.3.36 (2026-06-20). ~~scoped request, blocked on a BlazorBlocks publish (see §2). Confirmed at runtime against `Cerebellum.AuthBlocks.Web` 10.3.33 / `Cerebellum.BlazorBlocks.Web` 10.3.32. Author: product-designer (for a downstream consumer team). Date: 2026-06-19.~~

> **Resolution (2026-06-20):** `AddBlazorBlocksWeb()` landed in `Cerebellum.BlazorBlocks.Web` 10.3.33 and `ConfigureAuthServices` calls it in `Cerebellum.AuthBlocks.Web` 10.3.36; DeepDrftManager picked up 10.3.36 and removed its local `EditModalSaveContextHolder` stopgap.
> This brief is retained as historical record — no further action required.

**This is one half of a two-team, ordered fix. AuthBlocks ships second — see §2 and §9.**

---

## 1. The defect in one sentence

`AuthBlocksWeb` ships `Users.razor` and `Registrations.razor`, both of which render BlazorBlocks'
`<ModelView>` component — but `ConfigureAuthServices` (the single DI entry point consumers call to light up
the AuthBlocks Web surface) does **not** ensure `ModelView`'s required service
`Web.Maintenance.Entities.EditModalSaveContextHolder` is registered. So a consumer that wires up AuthBlocks
the normal way gets an unhandled `InvalidOperationException` that **terminates the Blazor circuit on
navigation** to either page, unless that consumer manually hand-registers an internal BlazorBlocks service
in its own `Program.cs`.

The fix: have `ConfigureAuthServices` call BlazorBlocks' new `AddBlazorBlocksWeb()` extension (which
registers the holder), so AuthBlocks stays self-contained for *its* consumers.

---

## 2. Blocking prerequisite — BlazorBlocks must ship first

This fix **cannot land until BlazorBlocks publishes a new `Cerebellum.BlazorBlocks.Web` version that
exposes a Web-side registration extension** (working name `AddBlazorBlocksWeb()`). That extension is what
actually registers `EditModalSaveContextHolder`; AuthBlocks' job is only to *call* it.

- AuthBlocks is currently on `Cerebellum.BlazorBlocks.Web` **10.3.32**, which has **no** such extension.
- The BlazorBlocks team is shipping the extension and bumping the package as the first half of this fix.
- **Reference the specific new version BlazorBlocks publishes for this fix** — fill in the exact version
  number once the BlazorBlocks team reports it. Do not proceed against 10.3.32; the method will not exist.

If you reach this work before the BlazorBlocks version is available, stop and wait for the published version
number. The AuthBlocks change is small once the prerequisite is in hand.

---

## 3. The confirmed failure

### Stack trace (captured from a consuming app on navigation to the Users admin page)

```
System.InvalidOperationException: Cannot provide a value for property 'SaveContextHolder' on type
'Web.Maintenance.Entities.ModelView`5[[AuthBlocksModels.InputModels.UserInputModel, ...],
[AuthBlocksModels.Models.UserModel, ...],[AuthBlocksWeb.Components.Pages.UserAdmin.Users.UserEditModal, ...],
[AuthBlocksWeb.Components.Pages.UserAdmin.Users.UsersViewModel, ...],
[AuthBlocksModels.Converters.UserModelToInputConverter, ...]]'.
There is no registered service of type 'Web.Maintenance.Entities.EditModalSaveContextHolder'.
   at Microsoft.AspNetCore.Components.ComponentFactory...CreatePropertyInjector...
```

`ModelView` declares `SaveContextHolder` as `required` with `[Inject]`, so Blazor's component factory
throws during component activation. There is no try/catch around component instantiation in the render path,
so the exception propagates and tears down the circuit. The user sees a dead page / "An unhandled error has
occurred" and must reload.

### Which AuthBlocks pages trigger it

`AuthBlocksWeb` ships two user-admin pages that render `<ModelView>`:

- `AuthBlocksWeb/Components/Pages/UserAdmin/Users/Users.razor`
- `AuthBlocksWeb/Components/Pages/UserAdmin/Registrations/Registrations.razor`

Any consumer that routes to either page hits the defect on first navigation.

---

## 4. Why this is AuthBlocks' gap to close (not the consumer's)

`AuthBlocksWeb/Startup.cs` exposes `ConfigureAuthServices(IServiceCollection, string apiBaseUrl)` — the
**single DI entry point** consumers call to light up the AuthBlocks Web surface. It already registers all
the user-admin viewmodels and clients (`UsersViewModel`, `RegistrationsViewModel`, `PermissionsViewModel`,
their clients, auth state, hierarchical authorization, etc.). It does **not** register
`EditModalSaveContextHolder` and does **not** call any BlazorBlocks Web extension.

So AuthBlocks ships pages that depend on `ModelView` while leaving one of `ModelView`'s required services
unregistered. The consumer is silently expected to fill the gap — and that is exactly what happened:
**two independent downstream products** each had to hand-register the internal BlazorBlocks service
(`AddScoped<Web.Maintenance.Entities.EditModalSaveContextHolder>()`) in their own `Program.cs` to make
AuthBlocks' shipped pages work. The whole value of a single `ConfigureAuthServices` entry point is that a
consumer calling it (plus the already-required `AddMudServices`) gets a working surface with zero manual
registrations. Today they don't. Closing this gap inside `ConfigureAuthServices` restores that promise.

Note: `IDialogService` / `ISnackbar` (also injected by `ModelView`) come from MudBlazor's
`AddMudServices()`, which every AuthBlocks Web consumer already calls as a documented prerequisite — those
are not the gap. The single library-owned gap is `EditModalSaveContextHolder`.

---

## 5. The fix

### 5.1 Bump the BlazorBlocks reference

Update the `Cerebellum.BlazorBlocks.Web` package reference (currently 10.3.32) to the new version
BlazorBlocks publishes for this fix (see §2 — fill in the exact version). This is what makes
`AddBlazorBlocksWeb()` available.

### 5.2 Call the extension from `ConfigureAuthServices`

```csharp
// AuthBlocksWeb/Startup.cs, inside ConfigureAuthServices(...)
services.AddBlazorBlocksWeb();   // registers EditModalSaveContextHolder for the ModelView-based pages
```

Order does not matter for this scoped service; place it near the other registrations. The
`AddBlazorBlocksWeb()` extension registers `EditModalSaveContextHolder` as scoped per circuit (its correct
lifetime — the holder is per-circuit mutable state that `ModelView` writes and `EditModelModal` reads).

### 5.3 Why this belongs in `ConfigureAuthServices`, not pushed onto consumers

- `ConfigureAuthServices` is AuthBlocks' **single DI entry point**. A consumer calling only
  `AddMudServices()` + `ConfigureAuthServices(...)` should get a fully working user-admin surface. Folding
  the BlazorBlocks call into the existing entry point keeps that promise; introducing a second method the
  consumer must remember to call (or expecting them to call `AddBlazorBlocksWeb()` themselves) just relocates
  the leaked registration one layer up.
- AuthBlocks must **not** register `EditModalSaveContextHolder` directly (reaching into BlazorBlocks'
  internal `Web.Maintenance.Entities` namespace) — that is the same smell the two consumers exhibited,
  merely relocated. Compose BlazorBlocks' own `Add*` extension instead; the registration lives with its
  owner, and AuthBlocks stays self-contained by calling it. This is the standard ASP.NET Core layering:
  each library exposes an `Add*` for its own services, and a higher-level library's `Add*` calls the lower
  one's.

---

## 6. Constraints

- **Do not register `EditModalSaveContextHolder` directly** in AuthBlocks. Call `AddBlazorBlocksWeb()`;
  let BlazorBlocks own its type (§5.3).
- **Keep `ConfigureAuthServices` the single AuthBlocks entry point.** Do not introduce a second method
  consumers must remember to call; fold the BlazorBlocks call into the existing one.
- **MudBlazor remains a caller-owned prerequisite.** AuthBlocks already relies on consumers calling
  `AddMudServices()` for all its MudBlazor-based pages; do not absorb it into `ConfigureAuthServices`.
- **Versioning:** AuthBlocks Web packs/pushes via its `pack.ps1` / packaging script. `AuthBlocksWeb` is
  currently `Cerebellum.AuthBlocks.Web` **10.3.33**; bump to the next version after referencing the new
  BlazorBlocks version and adding the `AddBlazorBlocksWeb()` call. **Record the new version** so consumers
  can pin.

---

## 7. Acceptance criteria

1. The `Cerebellum.BlazorBlocks.Web` package reference is bumped to the new version BlazorBlocks published
   for this fix, and `ConfigureAuthServices` calls `AddBlazorBlocksWeb()`.
2. A fresh consumer that calls **only** `AddMudServices()` and
   `AuthBlocksWeb.Startup.ConfigureAuthServices(...)` — and **registers nothing else by hand** — can
   navigate to the Users admin page and the Registrations admin page with **no `InvalidOperationException`**
   and **no circuit teardown**.
3. Working behavior means not just page load: opening the edit dialog on a user, saving a valid change,
   **succeeds** — i.e. the save bridge actually works end-to-end through AuthBlocks' pages.
4. No AuthBlocks consumer needs to touch `Web.Maintenance.Entities` directly; no manual registrations are
   required beyond the documented `AddMudServices`.
5. `AuthBlocksWeb` is published as a version bump from 10.3.33, and the new version number is recorded.

---

## 8. Open questions for the implementing team / its sponsor

1. **Exact BlazorBlocks version to reference.** Pending the BlazorBlocks team's publish (§2). Confirm the
   published version number and the exact extension method name (proposed `AddBlazorBlocksWeb()`) before
   landing the call.
2. **Placement within `ConfigureAuthServices`.** Anywhere in the method works (scoped service, order-
   independent). Confirm there is no existing convention in `Startup.cs` for grouping third-party `Add*`
   calls that this should follow.
3. **Any other AuthBlocks pages built on `ModelView`/`NewModelView`?** This brief identified Users and
   Registrations. If the team expects to add more maintenance pages, note that calling `AddBlazorBlocksWeb()`
   once covers them all (it is the single home for the maintenance-component deps).

---

## 9. Suggested reading order in the repo

1. `AuthBlocksWeb/Startup.cs` — `ConfigureAuthServices`, the single entry point; add the
   `AddBlazorBlocksWeb()` call here.
2. `AuthBlocksWeb/Components/Pages/UserAdmin/Users/Users.razor` — renders `<ModelView>`; triggers the
   defect on navigation.
3. `AuthBlocksWeb/Components/Pages/UserAdmin/Registrations/Registrations.razor` — the second page that
   renders `<ModelView>`.
4. The AuthBlocks Web `.csproj` — the `Cerebellum.BlazorBlocks.Web` package reference to bump.
5. The AuthBlocks `pack.ps1` / packaging script — to bump and publish `AuthBlocksWeb` after referencing the
   new BlazorBlocks version.

---

## 10. Cross-team ordering (important — you ship second)

This fix is layered across two repos and **must land in order**:

1. **BlazorBlocks ships first.** It adds `AddBlazorBlocksWeb()`, bumps `Cerebellum.BlazorBlocks.Web` from
   10.3.32, packs/pushes, and reports the new version number.
2. **Then AuthBlocks (this team)** bumps its `Cerebellum.BlazorBlocks.Web` reference to that published
   version, calls `AddBlazorBlocksWeb()` from `ConfigureAuthServices`, bumps `Cerebellum.AuthBlocks.Web` from
   10.3.33, and publishes.

This team **cannot complete its part until the BlazorBlocks version is published** (§2). Confirm that
version number is in hand before starting.
