---
title: slice-isolation
description: >-
type: skill
repository: https://github.com/TimeWarpEngineering/timewarp-architecture
---

>-

Maintained in [timewarp-architecture](https://github.com/TimeWarpEngineering/timewarp-architecture) · Canonical file: [SKILL.md](/skills/slice-isolation/SKILL.md)

## Install

```sh
npx skills add TimeWarpEngineering/timewarp-architecture --skill slice-isolation
```

Or copy the [SKILL.md](/skills/slice-isolation/SKILL.md) into your agent's skills directory.

---

# Slice isolation (TWA0009)

Slices are **independently removable vertical units**. Folders organize humans; the
**namespace under SliceRoot is the law**. Analyzer **TWA0009** is the reactive safety net;
this skill is for **correct first placement** so greenfield work does not couple product
areas by accident.

Enforcement ships in `TimeWarp.Architecture.Analyzers` (and monorepo ProjectReference). Do not
re-interpret rules here — mirror the analyzer.

## Detection — when to invoke

| Signal | How to find it |
|--------|----------------|
| Product area under `features/` | `web-spa/features/…`, `web-contracts/features/…` |
| Namespace under SliceRoot | `…Features.<Id>` (or nested `…Features.Admin.Roles`) |
| TWA0009 / `CrossSliceReference` | diagnostic text or attribute on a type |
| “Where does this page/state live?” | any new product capability before scaffolding |

## Terms

| Term | Meaning |
|------|---------|
| **Slice** | Removable vertical capability; the isolation unit |
| **Feature** | Informal product language only — not the analyzer’s unit name |
| **Module** | `IModule` / host DI composition — **not** a product slice |

Prefer saying **slice** in diagnostics, opt-outs, and agent prose. Namespace path may still use
`…Features.*` (familiar VSA / contracts layout).

## SliceRoot

| Setting | Value |
|---------|--------|
| Default | `{RootNamespace}.Features` (from MSBuild `RootNamespace`) |
| Override | MSBuild property `TimeWarpSliceRoot` (must be `CompilerVisibleProperty`) |

**Slice id** = path under SliceRoot after stripping structural suffixes `Pages`, `Components`,
`Application`. Nested ids are the **full path**:

| Namespace | Slice id / tier |
|-----------|-----------------|
| `…Features` | **Substrate** (bare root) |
| `…Features.Applications` | **Platform** id `Applications` |
| `…Features.Counters` | **Product** id `Counters` |
| `…Features.Counters.Pages` | **Product** id `Counters` (suffix stripped) |
| `…Features.Admin.Roles` | **Product** id `Admin.Roles` |
| `…Components`, layouts, app root types | **Outside** SliceRoot |

Folders usually mirror slices (`features/counter/` ↔ `…Features.Counters`) but **moving a file
does not change legal dependencies** — only the namespace does.

## Tiers (dependency rules)

| Tier | Example | May reference |
|------|---------|---------------|
| **Outside** | `…Components`, shell, layouts | Anything (composition free) |
| **Substrate** | bare `…Features` (`BaseComponent`, shared base types) | Outside, substrate, platform — **not** product without opt-out |
| **Platform** | `…Features.Applications` | Outside, substrate, platform — **not** product without opt-out |
| **Product** | `…Features.Counters`, `…Features.Admin.Roles` | Outside, substrate, platform, **own** product id, contracts (other assembly). **Not** another product id without opt-out |

**Forbidden without opt-out (TWA0009):**

- product A → product B (A ≠ B)
- platform → product
- substrate → product

**Free by design:**

- product → platform (`Applications`) — e.g. `CounterPage` → `ApplicationState`
- any code → **other assemblies** (contracts are sharing-by-design)
- Outside → product (nav shell, shared components)

## Placement matrix

| Artifact | Where |
|----------|--------|
| Page, state, actions, slice-local UI | **Inside** the product slice namespace |
| App chrome / shell / empty `MainLayout` | **Outside** SliceRoot (e.g. `…Components`) — see `blazor-layout` |
| Shared UI used by multiple slices | `components/` → namespace outside SliceRoot |
| Shared API shapes | **Contracts** project (other assembly; free under TWA0009) |
| Host-wide modal / menu / branding state | Platform `Applications` |

Living anchors (timewarp-architecture template):

| Role | Path | Namespace |
|------|------|-----------|
| Product | `web-spa/features/counter/` | `…Features.Counters` |
| Nested product | `web-spa/features/admin/roles/` | `…Features.Admin.Roles` |
| Platform | `web-spa/features/application/` | `…Features.Applications` |
| Substrate | `web-spa/features/base/base-component.cs` | `…Features` |
| Outside shell | `web-spa/components/TimeWarpPage.razor` | `…Components` |

## Greenfield scaffold workflow

1. **Name the slice** — plural, domain-oriented (`Clients`, `Admin.Roles`).
2. **Folder** — kebab path under the project’s `features/` tree (match sibling casing).
3. **Namespace** — `{RootNamespace}.Features.{SliceId}` (plural segments; nested with `.`).
4. **Colocate** page, state, actions, and slice-private components in that namespace (pages are
   **not** shared infrastructure — no grab-bag `…Pages` for product UI).
5. **Contracts** — same plural feature path under the contracts project (`web-api-contracts`
   skill). Other assembly → free across SPA slices.
6. **Wire nav / DI** from Outside or platform — not from another product slice.
7. **Prefer share** (Components / contracts) over `[CrossSliceReference]`.
8. **Build** — fix TWA0009 by relocating code first; mute only for deliberate demo/integration edges.

## Share vs opt-out

### Prefer share

- Promote shared controls to `…Components`.
- Share API shapes via contracts assembly.
- Depend product → platform without attributes when the dependency is real host state.

### Opt-out — deliberate edges only

```csharp
using TimeWarp.Foundation.Features;

[CrossSliceReference(typeof(CounterState), "Living style guide exercises the counter throw-exception pipeline.")]
partial class StyleGuidePage;
```

Rules:

- Attribute on the **referencing** type (`AllowMultiple = true` for multiple foreign slices).
- `typeof(T)` maps to the **target product slice**; only edges into that slice are suppressed.
- Reason must be non-empty (human paperwork).
- Partial-safe (semantic attributes).
- Type: `TimeWarp.Foundation.Features.CrossSliceReferenceAttribute` (package
  `TimeWarp.Foundation.Contracts` / monorepo foundation-contracts).

Living examples:

- Style guide → Counters: `web-spa/features/style-guide/pages/StyleGuidePage.razor.cs`
- Auth pipeline deliberate edges: authentication code-behinds with multiple
  `[CrossSliceReference(...)]` when needed

## Limits agents must know

| Limit | Implication |
|-------|-------------|
| **Same assembly only** | Contracts / NuGet metadata types never trip TWA0009 |
| **Hand-written C#** | `GeneratedCodeAnalysisFlags.None` — pure `.razor` without `.razor.cs` is not scanned; put deliberate edges on code-behind |
| **Folders can lie** | Namespace still owns the type |
| **Structural suffixes** | `…Counters.Pages` is still product id `Counters` |

## Good / bad examples

| Bad | Why | Fix |
|-----|-----|-----|
| `…Features.Counters` type uses `WeatherForecastsState` | product → product | Share via Components/contracts, or reasoned `[CrossSliceReference]` |
| Product page in grab-bag `…Pages` outside any slice | not removable with the capability | Namespace under `…Features.<Id>` |
| Platform type reaches into `Counters` | platform ↛ product | Invert dependency (product → platform) or rare opt-out on platform type |
| Mute TWA0009 globally / without reason | hides real coupling | Relocate or scoped opt-out |

| Good | Why |
|------|-----|
| `CounterPage` uses `ApplicationState` | product → platform free |
| `TimeWarpPage` in `…Components` | Outside composition free |
| `Admin.Roles` only uses own types + contracts + platform | nested product isolation |

## Agent checklist

- [ ] New capability has a slice id and matching `{Root}.Features.{Id}` namespace
- [ ] Page, state, and actions live in that namespace
- [ ] Shell/layout stay outside SliceRoot (or platform only when truly host state)
- [ ] Cross-slice data via Components or contracts first
- [ ] Any remaining edge has `[CrossSliceReference(typeof(T), "reason")]`
- [ ] No silent coupling or unexplained suppressions

## Related skills and pointers

- `web-api-contracts` — contract placement; **contracts assemblies are free** under TWA0009; still use plural `…Features.*` aligned with SPA product slices
- `blazor-layout` — empty layout + shell; chrome **outside** SliceRoot
- `blazor-css-strategy` — shell/component styling only
- `agent-context-regions` — Purpose/Design on new files (TWA0004)
- **AGENTS.md** — TWA diagnostic table (row TWA0009)
- **HowToRemoveDemoFeatures** — delete Counter/EventStream demo slices
- **Analyzer (source of truth):** `source/analyzers/timewarp-architecture-convention-analyzers/slice-isolation-analyzer.cs`
- **Opt-out attribute:** `source/foundation/foundation-contracts/base/cross-slice-reference-attribute.cs`
