# `T3.Board`
[🔗](https://github.com/dl-alexandre/t3-elixir/blob/main/lib/t3/board.ex#L1)

Pure board projection for ordinary orchestration shell/thread streams.

Fold chunk arrays and catch-up results with `apply/3`. The returned map is
keyed by `{host, thread_id}`, so IDs from different environments cannot collide.
A full shell snapshot replaces only that host's rows. Project-enrichment-only
snapshots do not clear rows. Sparse thread events preserve fields they do not
carry. Unknown event types are ignored.

    rows = T3.Board.apply(%{}, chunk_values, host: "local")
    rows = T3.Board.apply(rows, next_chunk_values, host: "local")

`normalize/2` exposes individual upserts/removals for callers keeping their own
cache. Its upserts can be partial (nil fields mean unavailable); use `apply/3`
when retaining prior fields and authoritative snapshot replacement matters.

Inputs must use ordinary, uncompressed projection bodies. Do not opt into
`acceptCompactIds`, `acceptDedupedBodies`, `acceptCompactTurnItems`, or deferred
work without restoring T3's projection format first. Timestamps and statuses
are wire strings. Snippets collapse whitespace and default to 160 graphemes.

# `key`

```elixir
@type key() :: {term(), String.t()}
```

# `apply`

```elixir
@spec apply(%{optional(key()) =&gt; T3.Board.Thread.t()}, map() | [map()], keyword()) ::
  map()
```

Fold a chunk, shell snapshot, or thread projection into a board cache.

# `normalize`

Return `{:upsert, row}` / `{:delete, thread_id}` operations for wire items.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
