The objective tree is what the work was for. One table. Display names the depths:
  • Product — root
  • Objective — slice of that product
  • Goal — deeper named slice (depth ≥ 2)
This is not Type (kind of work). A Goal on this tree is not the old word for Type.

Where to read it

PlaceWhat you see
Dashboard → ProductsEach trunk, with cost for the branch
Dashboard → ObjectivesSlices. Goals are clickable chips
assay objectivesTree + window counts
assay unplacedSittings with no winning window
Unknown sittings (no episode) are a card / a list. They are not a fake root.

Episodes

An episode is a range of turns in one sitting, with one primary node. Default: the whole sitting is one episode. Cap 8. No overlap at one version. Split when the sitting changed job (mixed). Do not split when one job also hit another product (theme) — use a touch. Spend follows the first episode at the winning source. Touches never take dollars.

Touches

A touch is an extra edge: this sitting also affected that node. Chips and counts only. Talk does not mint a touch. A write (or a declared scope) must match an accepted node that is not already a primary.

Proposed vs accepted

A judge may mint a proposed node. Leaves may not hang off a proposal. Accept it before it is a real trunk:
assay declare --accept --objective <id>

Placement

Retrieve-by-write runs on the sweep. It places a sitting when writes already name an accepted node. The labeler (after assay labelling on) places unplaced sittings using your AI.
assay unplaced
assay labelling run
assay attribute objectives
unplaced never calls a judge. It is the dump a labelling sitting reads. Hand place:
assay declare --session <id> --objective <node>
See Labelling and Framing.