---
title: "Products"
description: "What a product cost to build — tree placement and path mentions, two named readings."
---

"What did this product cost?" has **two honest stories**. Assay prints both and names which.

## Tree product

Placement on the objective tree. What the work was **for**. Spend follows the **first episode** at the winning source. See [Objectives](/objectives) and [Framing](/framing).

Dashboard → **Products**. Each trunk is a product. Unknown sittings are their own card, not a fake root named `other`.

## Path product

Derived from **path mentions** in the harness's own session documents. Not from `project` (that field is seating).

```bash
assay products
assay attribute products    # write the overlay (sweep already does this)
```

Every surface that prints this story shows **two** cost columns:

| Reading | What it is |
|---|---|
| **Inclusive** | Whole spend of every sitting that mentioned the product. Upper bound. Sessions may overlap. **Does not partition.** |
| **Weighted** | Sitting spend × share of that sitting's workspace refs. **Does partition.** Residuals must reconcile to priced spend. |

A breakdown you cannot tie back to the total is a breakdown nobody should trust. The weighted column plus every residual population adds up.

### Residuals (named, never merged)

| Bucket | Means |
|---|---|
| No evidence | The sitting was read. It referenced no workspace path. |
| Unscanned | There was no source document to read. |
| Unknown | Anything else that did not land on a product. |

A measured zero is **not** folded into unknown.

Every figure names its **counting unit**. Default is `line-distinct` (one line that names a component is one reference). An older unit stays reproducible and is never mixed into the default.

## The `products` map

A product name is a business fact. Config groups workspace folders:

```json
{
  "products": {
    "workspaceRoots": ["~/code"],
    "groups": {
      "website": ["marketing-site", "docs-site"]
    }
  }
}
```

| Key | Meaning |
|---|---|
| `workspaceRoots` | Where a **component** lives. The next path segment under a root is the component. Default `["~/code"]`. |
| `groups` | Product name → the components it is made of. Unnamed components stay products of their own. |

**A component may belong to at most one product.** Overlap would count the same refs twice and weighted would stop being a partition. Assay refuses that config at load.

`groups` is a **read-time** roll-up. The overlay is stored at component grain. Edit `groups` and every report relabels immediately. Nothing is re-derived.

Changing `workspaceRoots` changes the measurement. The next `attribute products` pass writes a new measurement.

With **no** `products` block the feature still works: each component is its own product.

## Filter

The console's `?product=` scope is the **inclusive** reading. Panels that do not apply it say so in words.

## CLI

```bash
assay products
assay products --product website
```
