# The plan's data format

The Project pages render from one file, [plan.yaml](https://tractat-us.github.io/bee/project/plan.yaml), checked against [plan.schema.json](https://tractat-us.github.io/bee/project/plan.schema.json) (JSON Schema 2020-12). Both are included below from the repo at build time, so this page can't drift from them.

## Shape

The format is chosen so a bee board can be seeded from it later:

- `items` is an object keyed by id. An id is opaque and stable, and is never reused. It starts with `task-` (a v1 plan task), `bee-` (a bee issue or PR), `kuilt-` (kuilt work) or `out-` (work outside the code). A slice keeps its draft id, such as `kuilt-3126-d`, once it is filed; its GitHub number lives only in `links`.
- Each item is replaced whole on write. On a board, that means a concurrent status move and summary edit on the same item keep only one of the two.
- `order` lists every id exactly once, in display order. On a board it is an Rga of ids.
- `columns` has one entry per status, and `column_order` puts them in order. On a board these are a `Board` notion's columns. A column with an `owner` is shown at the top of the [overview](https://tractat-us.github.io/bee/project/index.md) as waiting on that owner.
- `parent` names the item this one is part of. A parent depends on its children by definition, so a child is never also in its parent's `depends_on`.
- `started` is when the item's PR opened, or when its issue was filed if it has no PR. `landed` is when it merged or closed, or for a decision, when it was ruled. Only a done item has one.
- Timestamps are quoted UTC strings, `"2026-11-07T01:31Z"`. The pages show them in America/New_York.
- An `estimate` is a range, `low` to `high` in `hours` or `days`, with the `basis` it rests on and an optional `confidence`. The pages always label it as an estimate and never draw it on a dated axis.
- A relative link URL is relative to `docs/project/`, so it works on GitHub and on the site.

The YAML holds plain JSON values only: no anchors, no tags, no unquoted dates. Every item allows only the fields the schema lists, so an export from a board must bump `schema_version` before it adds one, and must drop duplicate and missing ids from `order`.

## Checks

The build fails when the file breaks the schema. Beyond the schema, it fails when:

- a mapping repeats a key;
- an `order`, `depends_on` or `parent` entry names an id that isn't an item, or an item is missing from `order`;
- `column_order` and `columns` name different statuses, or an item's status has no column;
- `depends_on` or `parent` has a cycle, or a parent's `depends_on` lists its own child;
- a timestamp or date isn't a real one, an item lands before it starts, or an item that isn't done has `landed`;
- an estimate's `low` is above its `high`;
- a title, summary or basis spans more than one line.

The checks live in [`docs-site/plan_pages.py`](https://github.com/tractat-us/bee/blob/main/docs-site/plan_pages.py). Every link on an item is rendered, so strict mode checks each one.

## The schema

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/tractat-us/bee/blob/main/docs/project/plan.schema.json",
  "title": "bee project plan",
  "description": "The project's plan as data: pieces of work, their status, dependencies and estimates. The docs site renders the Project section from it, and a bee board can be seeded from it: `items` is an object keyed by stable id (one object per item, replaced whole on write) and `order` is a list of ids (an Rga of ids on the board). Replacing an item whole means that on a board, a concurrent status move and summary edit on the same item keep only one of the two. Every value is plain JSON, so the YAML that holds it uses no anchors, tags or unquoted dates. A future export from a board must drop duplicate and missing ids from `order`, and must bump `schema_version` before adding any field, since an item allows no properties beyond those listed here.",
  "type": "object",
  "additionalProperties": false,
  "required": ["schema_version", "as_of", "columns", "column_order", "order", "items"],
  "properties": {
    "schema_version": { "const": 1 },
    "as_of": {
      "description": "When the file was last reconciled with GitHub, as an ISO 8601 UTC timestamp.",
      "$ref": "#/$defs/timestamp"
    },
    "sources": {
      "description": "Where the data comes from, in reading order.",
      "type": "array",
      "items": { "$ref": "#/$defs/link" }
    },
    "columns": {
      "description": "One column per status. On a board, these are a Board notion's columns.",
      "type": "object",
      "propertyNames": { "$ref": "#/$defs/status" },
      "additionalProperties": {
        "type": "object",
        "additionalProperties": false,
        "required": ["title"],
        "properties": {
          "title": { "type": "string" },
          "owner": { "description": "Who moves items out of this column, when that is one party.", "type": "string" }
        }
      }
    },
    "column_order": {
      "type": "array",
      "items": { "$ref": "#/$defs/status" },
      "uniqueItems": true
    },
    "order": {
      "description": "Every item id exactly once, in display order. The docs build fails on a duplicate, a missing id or an id that is not an item.",
      "type": "array",
      "items": { "$ref": "#/$defs/id" },
      "uniqueItems": true
    },
    "items": {
      "type": "object",
      "propertyNames": { "$ref": "#/$defs/id" },
      "additionalProperties": { "$ref": "#/$defs/item" }
    }
  },
  "$defs": {
    "id": {
      "description": "Opaque, stable and never reused. Prefixes: task- (a plan task), bee- (a bee issue or PR), kuilt- (a kuilt issue or PR), out- (work outside the code). A slice keeps its draft id (kuilt-3126-d) once it is filed; its GitHub number lives only in `links`.",
      "type": "string",
      "pattern": "^(task|bee|kuilt|out)-[a-z0-9]+(-[a-z0-9]+)*$"
    },
    "status": {
      "enum": ["done", "in-flight", "next", "blocked", "waiting-on-iain", "later"]
    },
    "timestamp": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2})?Z$"
    },
    "date": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "link": {
      "type": "object",
      "additionalProperties": false,
      "required": ["title", "url"],
      "properties": {
        "title": { "type": "string" },
        "url": { "type": "string", "pattern": "^(https://|\\.\\./|\\./|[A-Za-z0-9_])" }
      }
    },
    "estimate": {
      "description": "A range, always labelled as an estimate, with what it rests on. Wall-clock time from start to merge, not counting time waiting on Iain.",
      "type": "object",
      "additionalProperties": false,
      "required": ["low", "high", "unit", "basis"],
      "properties": {
        "low": { "description": "At most `high`.", "type": "number", "minimum": 0 },
        "high": { "type": "number", "minimum": 0 },
        "unit": { "enum": ["hours", "days"] },
        "basis": { "description": "Why this range: the merge history or plan text it comes from.", "type": "string" },
        "confidence": { "enum": ["low", "medium", "high"] }
      }
    },
    "ruling": {
      "type": "object",
      "additionalProperties": false,
      "required": ["date", "summary"],
      "properties": {
        "date": { "$ref": "#/$defs/date" },
        "summary": { "type": "string" },
        "url": { "type": "string" }
      }
    },
    "item": {
      "type": "object",
      "additionalProperties": false,
      "required": ["kind", "title", "status"],
      "properties": {
        "kind": {
          "description": "task: a task in the v1 plan. pr: a pull request. issue: a bug or follow-up. decision: a question for Iain. kuilt: kuilt work bee depends on. outside: work outside the code.",
          "enum": ["task", "pr", "issue", "decision", "kuilt", "outside"]
        },
        "title": { "type": "string" },
        "status": { "$ref": "#/$defs/status" },
        "summary": { "description": "One sentence: what it is, or what it waits for.", "type": "string" },
        "parent": { "description": "The item this one is part of. A parent depends on its children by definition, so a child never appears in its parent's `depends_on`; the docs build fails if it does.", "$ref": "#/$defs/id" },
        "depends_on": {
          "description": "Items that must be done before this one can finish, other than its children. The docs build fails on a cycle.",
          "type": "array",
          "items": { "$ref": "#/$defs/id" },
          "uniqueItems": true
        },
        "started": { "description": "When its PR opened, or when its issue was filed if there is no PR.", "$ref": "#/$defs/timestamp" },
        "landed": { "description": "When it merged or closed; for a decision, when it was ruled. Required when status is done, and allowed only then. Never before `started`.", "$ref": "#/$defs/timestamp" },
        "estimate": { "$ref": "#/$defs/estimate" },
        "ruling": { "$ref": "#/$defs/ruling" },
        "links": {
          "type": "array",
          "items": { "$ref": "#/$defs/link" }
        }
      },
      "allOf": [
        {
          "if": { "properties": { "status": { "const": "done" } } },
          "then": { "required": ["landed"] }
        }
      ]
    }
  }
}
```

## The data

plan.yaml, in full

```yaml
# The bee project plan, as data. Schema: plan.schema.json, beside this file.
#
# The docs site's Project section renders from this file, and a bee board can later
# be seeded from it (bee#21). Keep it plain JSON in YAML form: no anchors, no tags,
# every timestamp a quoted UTC string. `items` is keyed by stable id and each item is
# replaced whole on write; `order` lists every id once. The markdown plan
# (docs/superpowers/plans/2026-11-06-bee-v1.md) stays the source of truth for what
# each task is; this file tracks where each one stands.
#
# Estimates are ranges, labelled as estimates, with their basis. They measure
# wall-clock time from start to merge and leave out time waiting on Iain.

schema_version: 1
as_of: "2026-11-08T19:02Z"

sources:
  - title: "v1 plan"
    url: "../superpowers/plans/2026-11-06-bee-v1.md"
  - title: "Epic: bee v1 (bee#6)"
    url: "https://github.com/tractat-us/bee/issues/6"
  - title: "Merged pull requests"
    url: "https://github.com/tractat-us/bee/pulls?q=is%3Apr+is%3Amerged"

columns:
  done: { title: "Done" }
  in-flight: { title: "In flight" }
  waiting-on-iain: { title: "Waiting on Iain", owner: "iain" }
  blocked: { title: "Blocked" }
  next: { title: "Next" }
  later: { title: "Later" }

column_order: [done, in-flight, waiting-on-iain, blocked, next, later]

order:
  - task-1
  - task-2
  - task-3
  - task-4
  - task-5
  - task-6
  - bee-11
  - task-7
  - bee-27
  - bee-28
  - bee-32
  - bee-31
  - bee-33
  - bee-37
  - bee-40
  - bee-43
  - bee-44
  - bee-45
  - bee-46
  - bee-49
  - bee-53
  - bee-54
  - bee-58
  - bee-60
  - bee-64
  - bee-65
  - bee-71
  - bee-72
  - bee-73
  - bee-74
  - bee-77
  - bee-78
  - bee-80
  - bee-81
  - bee-83
  - bee-84
  - bee-85
  - bee-14
  - bee-19
  - bee-23
  - task-8
  - task-9
  - task-10
  - bee-42-calls
  - task-11
  - bee-21
  - kuilt-3126
  - kuilt-3132
  - kuilt-3136
  - kuilt-3137
  - kuilt-3126-d
  - kuilt-3126-e
  - kuilt-3126-f
  - kuilt-3126-g
  - kuilt-3133
  - kuilt-3134
  - kuilt-3129
  - kuilt-3142
  - kuilt-3143
  - kuilt-3144
  - kuilt-3145
  - kuilt-3146
  - kuilt-own-write-ack
  - kuilt-3148
  - kuilt-3149
  - kuilt-3150
  - bee-42-hand-check
  - bee-auto-close
  - out-cla
  - out-kuilt-references

items:
  # ── The v1 plan's tasks ──────────────────────────────────────────────
  task-1:
    kind: task
    title: "Kotlin/wasm and the renderer in one page (spike 1)"
    status: done
    summary: "Kotlin/wasm drives the stock A2UI Lit renderer, with the build and CI."
    started: "2026-11-07T00:59Z"
    landed: "2026-11-07T01:31Z"
    links:
      - { title: "Plan, Task 1", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-1-kotlinwasm-and-the-renderer-in-one-page-spike-1-plus-all-build-wiring" }
      - { title: "bee#8", url: "https://github.com/tractat-us/bee/pull/8" }
      - { title: "Spike 1 report", url: "../spikes/2026-11-spike-1-renderer-glue.md" }

  task-2:
    kind: task
    title: "The board lattice and its projection (spike 2, part 1)"
    status: done
    depends_on: [task-1]
    started: "2026-11-07T01:38Z"
    landed: "2026-11-07T02:02Z"
    links:
      - { title: "Plan, Task 2", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-2-the-board-lattice-and-its-projection-spike-2-part-1" }
      - { title: "bee#9", url: "https://github.com/tractat-us/bee/pull/9" }
      - { title: "Spike 2 report", url: "../spikes/2026-11-spike-2-crdt-behind-a2ui.md" }

  task-3:
    kind: task
    title: "The relay (spike 2, part 2)"
    status: done
    depends_on: [task-2]
    started: "2026-11-07T02:13Z"
    landed: "2026-11-07T02:44Z"
    links:
      - { title: "Plan, Task 3", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-3-the-relay-spike-2-part-2" }
      - { title: "bee#15", url: "https://github.com/tractat-us/bee/pull/15" }
      - { title: "bee#29, deltas not whole boards", url: "https://github.com/tractat-us/bee/pull/29" }

  task-4:
    kind: task
    title: "The browser driver and two browsers (spike 2, part 3)"
    status: done
    depends_on: [task-3]
    started: "2026-11-07T02:55Z"
    landed: "2026-11-07T03:30Z"
    links:
      - { title: "Plan, Task 4", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-4-the-browser-driver-and-two-browsers-spike-2-part-3" }
      - { title: "bee#16", url: "https://github.com/tractat-us/bee/pull/16" }

  task-5:
    kind: task
    title: "Bridge mechanics (spike 3, first half)"
    status: done
    depends_on: [task-1]
    started: "2026-11-07T01:47Z"
    landed: "2026-11-07T02:12Z"
    links:
      - { title: "Plan, Task 5", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-5-bridge-mechanics-spike-3-first-half" }
      - { title: "bee#13", url: "https://github.com/tractat-us/bee/pull/13" }
      - { title: "Spike 3 report", url: "../spikes/2026-11-spike-3-bridge-mechanics.md" }

  task-6:
    kind: task
    title: "Claims (spike 4)"
    status: done
    summary: "Exactly-once claims with fencing tokens, through a durable voter that never claims. Held about a day on kuilt learner admission (bee#11)."
    depends_on: [task-1]
    started: "2026-11-07T01:42Z"
    landed: "2026-11-08T00:00Z"
    links:
      - { title: "Plan, Task 6", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-6-claims-spike-4" }
      - { title: "bee#10", url: "https://github.com/tractat-us/bee/pull/10" }
      - { title: "bee#26, learner grace", url: "https://github.com/tractat-us/bee/pull/26" }
      - { title: "Spike 4 report", url: "../spikes/2026-11-spike-4-claims.md" }

  bee-11:
    kind: decision
    title: "Claims blocked by kuilt learner admission: fix kuilt first, or work around it in bee?"
    status: done
    parent: task-6
    started: "2026-11-07T01:44Z"
    landed: "2026-11-07T14:43Z"
    ruling:
      date: "2026-11-07"
      summary: "Fix kuilt first: a learner reconciler, then removal after a grace (kuilt#3120). bee bumps its kuilt pin and finishes Task 6 once kuilt publishes."
      url: "https://github.com/tractat-us/bee/issues/11#issuecomment-6708367111"
    links:
      - { title: "bee#11", url: "https://github.com/tractat-us/bee/issues/11" }

  task-7:
    kind: task
    title: "Join, which completes spikes 3 and 4"
    status: done
    summary: "A Claude session opens a surface, waits and answers; a second session sees it. Landed as #27, #32 and #33."
    depends_on: [task-4, task-5, task-6]
    started: "2026-11-07T21:49Z"
    landed: "2026-11-08T02:17Z"
    ruling:
      date: "2026-11-07"
      summary: "The post-Task-7 review hold is lifted. #27 lands first, then #32 and #33. Tasks 8, 9 and 10 start in parallel from main once #27 merges, and Iain reviews #27's deviations after the fact."
      url: "https://github.com/tractat-us/bee/issues/6#issuecomment-6715926429"
    links:
      - { title: "Plan, Task 7", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-7-join-which-completes-spikes-3-and-4" }

  task-8:
    kind: task
    title: "Sketch and the companion adapter (spike 5, the acceptance test)"
    status: done
    summary: "The brainstorming visual companion's screens run through bee: v1's done-when. Landed after Iain's rulings on #60 (page-side commit) and the Sketch size cap (none for v1)."
    depends_on: [bee-27, bee-60]
    started: "2026-11-08T02:13Z"
    landed: "2026-11-08T18:49Z"
    estimate:
      low: 2
      high: 24
      unit: hours
      basis: "One PR, larger than Tasks 2–5, which took about half an hour each from PR open to merge. The high end is Task 6's 22 h, for a task that meets a kuilt or renderer gap."
      confidence: low
    links:
      - { title: "Plan, Task 8", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-8-sketch-and-the-companion-adapter-spike-5-the-acceptance-test" }
      - { title: "bee#38", url: "https://github.com/tractat-us/bee/pull/38" }

  task-9:
    kind: task
    title: "Durability of the board (spike 6)"
    status: done
    summary: "The board survives host restarts and closed browsers, through a generic Quilter–DurableStore adapter."
    depends_on: [bee-27]
    started: "2026-11-08T02:15Z"
    landed: "2026-11-08T03:21Z"
    links:
      - { title: "Plan, Task 9", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-9-durability-of-the-board-spike-6" }
      - { title: "bee#39", url: "https://github.com/tractat-us/bee/pull/39" }

  task-10:
    kind: task
    title: "A second screen, joined by LAN pairing (spike 7)"
    status: done
    summary: "A key, with Bluetooth-style passkey pairing; only human peers admit a device. Pairing runs by poll at /pair with a join budget (SSE until bee#211); the keyed sockets take a frame bound (kuilt#3145)."
    depends_on: [bee-27]
    started: "2026-11-08T02:20Z"
    landed: "2026-11-08T03:51Z"
    links:
      - { title: "Plan, Task 10", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-10-a-second-screen-spike-7" }
      - { title: "bee#42", url: "https://github.com/tractat-us/bee/pull/42" }

  bee-42-calls:
    kind: decision
    title: "Task 10's follow-up calls"
    status: done
    summary: "Four calls from #42, each now an issue: the host's PeerKind (#71), claim-free join records with a bridge refusal (#72), HTTPS on the LAN (#73, after the demo) and a host per writing e2e file (#74)."
    started: "2026-11-08T02:35Z"
    landed: "2026-11-08T17:26Z"
    ruling:
      date: "2026-11-08"
      summary: "Add PeerKind.Host as a label; accept claim-free admits and have the bridge refuse pairing surfaces; HTTPS on the LAN after the demo; a host per e2e file that writes records."
      url: "https://github.com/tractat-us/bee/issues/6#issuecomment-6724665300"
    links:
      - { title: "bee#42", url: "https://github.com/tractat-us/bee/pull/42" }

  task-11:
    kind: task
    title: "Working-day surfaces: Board, Poll, orphan decisions, history strip"
    status: done
    summary: "Landed in two halves without bee#19: Poll, Board and the history strip (#70), then orphan decisions and reassigned claims reaching a session's wait (#75). The Board needs no change when #19 makes card order an Rga."
    depends_on: [task-7]
    started: "2026-11-08T17:44Z"
    landed: "2026-11-08T18:59Z"
    links:
      - { title: "Plan, Task 11", url: "../superpowers/plans/2026-11-06-bee-v1.md#task-11-working-day-surfaces-board-poll-orphan-decisions-history-strip" }
      - { title: "bee#70, Notions Poll and Board", url: "https://github.com/tractat-us/bee/pull/70" }
      - { title: "bee#75, orphan decisions", url: "https://github.com/tractat-us/bee/pull/75" }

  # ── bee pull requests and issues ─────────────────────────────────────
  bee-27:
    kind: pr
    title: "Join the bridge, the board and claims"
    status: done
    parent: task-7
    started: "2026-11-07T21:49Z"
    landed: "2026-11-08T02:01Z"
    links:
      - { title: "bee#27", url: "https://github.com/tractat-us/bee/pull/27" }

  bee-28:
    kind: decision
    title: "Detect a dead board link from the claims link, or from a per-spoke view?"
    status: done
    parent: task-7
    started: "2026-11-07T21:51Z"
    landed: "2026-11-07T23:53Z"
    ruling:
      date: "2026-11-07"
      summary: "Detect a crash from the claims link: a node dropped after its learner grace is a PeerLost."
      url: "https://github.com/tractat-us/bee/issues/28#issuecomment-6714701528"
    links:
      - { title: "bee#28", url: "https://github.com/tractat-us/bee/issues/28" }

  bee-32:
    kind: pr
    title: "Detect a crashed agent from its claims link"
    status: done
    parent: task-7
    depends_on: [bee-27, bee-28]
    started: "2026-11-08T00:27Z"
    landed: "2026-11-08T02:10Z"
    links:
      - { title: "bee#32", url: "https://github.com/tractat-us/bee/pull/32" }

  bee-31:
    kind: issue
    title: "A late win whose link dies is released only by a later wait on that surface"
    status: done
    parent: task-7
    started: "2026-11-08T00:23Z"
    landed: "2026-11-08T02:17Z"
    links:
      - { title: "bee#31", url: "https://github.com/tractat-us/bee/issues/31" }

  bee-33:
    kind: pr
    title: "Give back a late win whose claims link died, on the next link"
    status: done
    parent: bee-31
    depends_on: [bee-27]
    started: "2026-11-08T01:18Z"
    landed: "2026-11-08T02:17Z"
    links:
      - { title: "bee#33", url: "https://github.com/tractat-us/bee/pull/33" }

  bee-37:
    kind: issue
    title: "A wait's reserve can no longer fail, so make it fail loudly"
    status: done
    summary: "A follow-up from #33's re-review. Fixed by #41."
    depends_on: [bee-33]
    started: "2026-11-08T02:10Z"
    landed: "2026-11-08T02:28Z"
    links:
      - { title: "bee#37", url: "https://github.com/tractat-us/bee/issues/37" }
      - { title: "bee#41", url: "https://github.com/tractat-us/bee/pull/41" }

  bee-40:
    kind: pr
    title: "Move kuilt to 0.7.0-dev.1696"
    status: done
    summary: "Takes kuilt's LatticeDotFun and CausalMap, slices (a) and (b) of kuilt#3126."
    depends_on: [kuilt-3132, kuilt-3136]
    started: "2026-11-08T02:15Z"
    landed: "2026-11-08T02:19Z"
    links:
      - { title: "bee#40", url: "https://github.com/tractat-us/bee/pull/40" }

  bee-43:
    kind: issue
    title: "A board change elsewhere may re-create the field someone is typing in"
    status: done
    summary: "Not a bee bug: the field is never re-created. The caret failures came from Playwright on macOS, and #63 pins the claim."
    started: "2026-11-08T02:36Z"
    landed: "2026-11-08T19:00Z"
    ruling:
      date: "2026-11-08"
      summary: "Not a bug."
      url: "https://github.com/tractat-us/bee/issues/43#issuecomment-6725706047"
    links:
      - { title: "bee#43", url: "https://github.com/tractat-us/bee/issues/43" }
      - { title: "bee#63", url: "https://github.com/tractat-us/bee/pull/63" }

  bee-44:
    kind: decision
    title: "Decision: an agent that dies while the host is down keeps its claims forever"
    status: done
    summary: "Built in #62: once a 60 s boot grace has passed, the host departs, as Crashed, any agent that holds a claim and has no presence entry."
    started: "2026-11-08T02:36Z"
    landed: "2026-11-08T17:26Z"
    ruling:
      date: "2026-11-08"
      summary: "Option (a), a boot grace."
      url: "https://github.com/tractat-us/bee/issues/44#issuecomment-6724665507"
    links:
      - { title: "bee#44", url: "https://github.com/tractat-us/bee/issues/44" }
      - { title: "bee#62", url: "https://github.com/tractat-us/bee/pull/62" }

  bee-45:
    kind: issue
    title: "Any website open on the laptop can use the board: check Origin and Host on /ws/*"
    status: done
    summary: "Fixed by #51, which refuses a board socket from another site or a rebinding host name."
    started: "2026-11-08T02:44Z"
    landed: "2026-11-08T04:40Z"
    links:
      - { title: "bee#45", url: "https://github.com/tractat-us/bee/issues/45" }
      - { title: "bee#51", url: "https://github.com/tractat-us/bee/pull/51" }

  bee-46:
    kind: issue
    title: "A tab left open across a host wipe pushes its old board, claim views included, into the new host"
    status: done
    summary: "Fixed by #52: every board and claims socket names its board, and the host refuses any other id before the upgrade. The id now lives in claims/ too, so moving claims/ aside starts a new board. Data from before #52 keeps its board, and a refused bridge exits loudly."
    started: "2026-11-08T03:07Z"
    landed: "2026-11-08T04:49Z"
    links:
      - { title: "bee#46", url: "https://github.com/tractat-us/bee/issues/46" }
      - { title: "bee#52", url: "https://github.com/tractat-us/bee/pull/52" }

  bee-53:
    kind: issue
    title: "ClaimsSmokeTest and FrameBoundTest fail intermittently in the smoke job"
    status: done
    summary: "Fixed by #57 for ClaimsSmokeTest, which now waits on conditions, not time. FrameBoundTest's missing 1009 close frame is #58."
    started: "2026-11-08T04:31Z"
    landed: "2026-11-08T05:27Z"
    links:
      - { title: "bee#53", url: "https://github.com/tractat-us/bee/issues/53" }
      - { title: "bee#57", url: "https://github.com/tractat-us/bee/pull/57" }

  bee-54:
    kind: issue
    title: "Refuse cross-site requests by Fetch Metadata: a no-Origin GET can still fill the pairing slots"
    status: done
    summary: "A follow-up to #51, fixed by #55."
    started: "2026-11-08T04:40Z"
    landed: "2026-11-08T05:36Z"
    links:
      - { title: "bee#54", url: "https://github.com/tractat-us/bee/issues/54" }
      - { title: "bee#55", url: "https://github.com/tractat-us/bee/pull/55" }

  bee-58:
    kind: decision
    title: "The host can hang up on an over-bound frame without its 1009 close frame"
    status: done
    summary: "Fixed by #69: bee moves to Ktor 3.6.1, which carries the upstream fixes for the lost last frame."
    started: "2026-11-08T05:15Z"
    landed: "2026-11-08T17:35Z"
    ruling:
      date: "2026-11-08"
      summary: "The host must deliver the 1009; done by moving Ktor to 3.6.1."
      url: "https://github.com/tractat-us/bee/issues/58#issuecomment-6724762759"
    links:
      - { title: "bee#58", url: "https://github.com/tractat-us/bee/issues/58" }
      - { title: "bee#69", url: "https://github.com/tractat-us/bee/pull/69" }

  bee-60:
    kind: decision
    title: "Decision: a Sketch can forge the viewer's choice in Chromium, by focusing itself"
    status: done
    summary: "Fixed in #38: a Sketch only proposes a choice, and the page records it on a trusted click on its own Send bar."
    started: "2026-11-08T06:01Z"
    landed: "2026-11-08T17:35Z"
    ruling:
      date: "2026-11-08"
      summary: "Option (a): the page commits the choice, outside the frame."
      url: "https://github.com/tractat-us/bee/issues/60#issuecomment-6724762579"
    links:
      - { title: "bee#60", url: "https://github.com/tractat-us/bee/issues/60" }
      - { title: "bee#38", url: "https://github.com/tractat-us/bee/pull/38" }

  bee-49:
    kind: decision
    title: "A Sketch can still reach the network through WebRTC, which CSP doesn't cover"
    status: done
    started: "2026-11-08T03:41Z"
    landed: "2026-11-08T17:30Z"
    ruling:
      date: "2026-11-08"
      summary: "Accepted as a v1 limit and documented in the spec; revisit when an engine ships a control."
      url: "https://github.com/tractat-us/bee/issues/49#issuecomment-6724762977"
    links:
      - { title: "bee#49", url: "https://github.com/tractat-us/bee/issues/49" }
      - { title: "bee#66, spec limit", url: "https://github.com/tractat-us/bee/pull/66" }

  bee-64:
    kind: decision
    title: "Decision: any local process can admit a second screen by writing a human-attributed admit"
    status: done
    summary: "Resolved for v1 by #68, which states the limit in spec section 5.7. Connection-attested authors are kuilt#3149."
    started: "2026-11-08T17:33Z"
    landed: "2026-11-08T17:42Z"
    ruling:
      date: "2026-11-08"
      summary: "Option A for v1: state the limit. No new gate may rest on peer kind."
      url: "https://github.com/tractat-us/bee/issues/64#issuecomment-6724838405"
    links:
      - { title: "bee#64", url: "https://github.com/tractat-us/bee/issues/64" }
      - { title: "bee#68", url: "https://github.com/tractat-us/bee/pull/68" }

  bee-65:
    kind: issue
    title: "A client whose FullState is over the frame bound redials and resends it forever"
    status: in-flight
    summary: "A board over the bound should stop and say so; the fix is in review as #76."
    started: "2026-11-08T17:33Z"
    links:
      - { title: "bee#65", url: "https://github.com/tractat-us/bee/issues/65" }
      - { title: "bee#76", url: "https://github.com/tractat-us/bee/pull/76" }

  bee-71:
    kind: issue
    title: "Give the host its own peer kind, and keep bee_clear off its surfaces"
    status: next
    summary: "PeerKind.Host as a label only, so bee_clear stops stranding pairing devices (from #42's calls)."
    started: "2026-11-08T17:44Z"
    links:
      - { title: "bee#71", url: "https://github.com/tractat-us/bee/issues/71" }

  bee-72:
    kind: issue
    title: "The bridge refuses wait and list on the host's pairing surfaces"
    status: next
    summary: "Claim-free admits stay, written into the spec, and the bridge refuses an agent that waits on a pairing surface (from #42's calls)."
    started: "2026-11-08T17:44Z"
    links:
      - { title: "bee#72", url: "https://github.com/tractat-us/bee/issues/72" }

  bee-73:
    kind: issue
    title: "Serve the board over HTTPS on the LAN, so LAN pages are secure contexts"
    status: later
    summary: "After the demo: plain-HTTP LAN pages keep no local copy and lack microphone, wake lock and clipboard (from #42's calls)."
    started: "2026-11-08T17:44Z"
    links:
      - { title: "bee#73", url: "https://github.com/tractat-us/bee/issues/73" }

  bee-74:
    kind: issue
    title: "Give each e2e spec that writes records its own host, and run two workers"
    status: next
    summary: "Saves about 45 s per smoke job; the PRs it waited on, #38 and #63, have merged (from #42's calls)."
    started: "2026-11-08T17:44Z"
    links:
      - { title: "bee#74", url: "https://github.com/tractat-us/bee/issues/74" }

  bee-77:
    kind: issue
    title: "The bridge's board socket sends no pings, so a half-open link can outlast the boot grace"
    status: next
    summary: "Set a client ping on the bridge's board and claims sockets, well under the 60 s grace."
    started: "2026-11-08T17:52Z"
    links:
      - { title: "bee#77", url: "https://github.com/tractat-us/bee/issues/77" }

  bee-78:
    kind: issue
    title: "Boot grace: two survivors holding different stale entries make a dead agent look seen"
    status: next
    summary: "A narrow window found in #62; count an identity as seen only when its newest entry names a voter member."
    started: "2026-11-08T17:52Z"
    links:
      - { title: "bee#78", url: "https://github.com/tractat-us/bee/issues/78" }

  bee-80:
    kind: issue
    title: "A bee-notions edit can ship a stale bundle while webpack reports up to date"
    status: next
    summary: "Declare bee-notions/src as an input to the webpack task, so a stale bundle can't read as a false green."
    started: "2026-11-08T17:59Z"
    links:
      - { title: "bee#80", url: "https://github.com/tractat-us/bee/issues/80" }

  bee-81:
    kind: issue
    title: "The bridge can't append to an array, so agent Polls lose their options basis"
    status: next
    summary: "bee_surface_open writes options as one whole-array leaf, so the bridge needs an append write."
    started: "2026-11-08T18:10Z"
    links:
      - { title: "bee#81", url: "https://github.com/tractat-us/bee/issues/81" }

  bee-83:
    kind: issue
    title: "Fence an orphan decision's proposal by the orphan token"
    status: next
    summary: "A stale click on an orphan decision applies to whatever orphaning is current; found in #75's re-review."
    started: "2026-11-08T18:40Z"
    links:
      - { title: "bee#83", url: "https://github.com/tractat-us/bee/issues/83" }

  bee-84:
    kind: issue
    title: "Sketch Send bar: close the remaining arming gaps with aria-disabled and a click guard"
    status: next
    summary: "Narrow holes left after #38's final review found it safe for a demo-stage v1."
    started: "2026-11-08T18:49Z"
    links:
      - { title: "bee#84", url: "https://github.com/tractat-us/bee/issues/84" }

  bee-85:
    kind: issue
    title: "PairingChannelTest's hang-up case fails every time it runs alone"
    status: next
    summary: "It passes inside a full check and failed once in CI; the pairing ends before the device hangs up."
    started: "2026-11-08T18:59Z"
    links:
      - { title: "bee#85", url: "https://github.com/tractat-us/bee/issues/85" }

  bee-14:
    kind: decision
    title: "Surface data semantics: merge or replace, concurrent card order, leaf encoding"
    status: done
    started: "2026-11-07T01:51Z"
    landed: "2026-11-07T14:43Z"
    ruling:
      date: "2026-11-07"
      summary: "Object writes replace, card order is an Rga of ids, and the prefix leaf encoding stands."
      url: "https://github.com/tractat-us/bee/issues/14#issuecomment-6708367416"
    links:
      - { title: "bee#14", url: "https://github.com/tractat-us/bee/issues/14" }

  bee-19:
    kind: pr
    title: "Surface data semantics: object writes replace, card order is an Rga of ids"
    status: blocked
    summary: "On hold until kuilt#3126 (d), the JsonCrdt v2 core, publishes."
    depends_on: [bee-14, kuilt-3126-d]
    started: "2026-11-07T14:51Z"
    links:
      - { title: "bee#19", url: "https://github.com/tractat-us/bee/pull/19" }

  bee-23:
    kind: issue
    title: "ClaimTable: drop duplicate log entries through kuilt's ClientSessionTable"
    status: blocked
    summary: "Before production. Can't happen within one incarnation on the pinned kuilt. Closing a session needs kuilt's RoomHost tear contract, kuilt#3129 (bee#30)."
    depends_on: [kuilt-3129]
    started: "2026-11-07T20:43Z"
    links:
      - { title: "bee#23", url: "https://github.com/tractat-us/bee/issues/23" }

  bee-21:
    kind: issue
    title: "Dogfood: bee as the board for its own development"
    status: later
    summary: "A first try is possible now that Task 9 has landed; the full version is Task 11's secondary test. The markdown stays the source of truth for now (ruled 2026-11-07)."
    depends_on: [task-7, task-8, task-9, task-11]
    links:
      - { title: "bee#21", url: "https://github.com/tractat-us/bee/issues/21" }

  # ── kuilt dependencies ───────────────────────────────────────────────
  kuilt-3126:
    kind: kuilt
    title: "Shared causal context for JsonCrdt (epic)"
    status: in-flight
    summary: "Began as an ORMap.remove bug; ruled reset-and-replace, re-seed migration, and every nested use on a shared-context CausalMap. Split into (a)–(g)."
    started: "2026-11-07T19:36Z"
    estimate:
      low: 1
      high: 3
      unit: days
      basis: "From the issue being filed to the last slice merging. (a) and (b) each took about 3 h from PR open to merge. (c) waits on three design calls for Iain, with no PR yet, and (d)–(g) are not filed. What remains is a chain of three: (c), then (d), then (e)–(g) in parallel, at 3–12 h each."
      confidence: low
    ruling:
      date: "2026-11-07"
      summary: "Reset and replace; migrate by re-seed; move every nested use to the shared-context CausalMap. The (a)–(g) split is confirmed."
      url: "https://github.com/tractat-us/kuilt/issues/3126"
    links:
      - { title: "kuilt#3126", url: "https://github.com/tractat-us/kuilt/issues/3126" }

  kuilt-3132:
    kind: kuilt
    title: "(a) LatticeDotFun, a dot store that joins its payloads"
    status: done
    summary: "Published in kuilt 0.7.0-dev.1696."
    parent: kuilt-3126
    started: "2026-11-07T22:27Z"
    landed: "2026-11-08T01:29Z"
    links:
      - { title: "kuilt#3132", url: "https://github.com/tractat-us/kuilt/pull/3132" }

  kuilt-3136:
    kind: kuilt
    title: "(b) CausalMap, one shared context for a map and its nested stores"
    status: done
    summary: "Published in kuilt 0.7.0-dev.1696."
    parent: kuilt-3126
    depends_on: [kuilt-3132]
    started: "2026-11-07T23:01Z"
    landed: "2026-11-08T01:43Z"
    links:
      - { title: "kuilt#3136", url: "https://github.com/tractat-us/kuilt/pull/3136" }

  kuilt-3137:
    kind: kuilt
    title: "(c) A dot-store Rga"
    status: waiting-on-iain
    parent: kuilt-3126
    summary: "A design gate is posted, with three calls for Iain before implementation. bee#19 and Task 11 wait on the chain that starts here."
    started: "2026-11-07T23:54Z"
    links:
      - { title: "kuilt#3137", url: "https://github.com/tractat-us/kuilt/issues/3137" }
      - { title: "Design gate", url: "https://github.com/tractat-us/kuilt/issues/3137#issuecomment-6716124347" }

  kuilt-3126-d:
    kind: kuilt
    title: "(d) JsonCrdt v2 core and path API"
    status: next
    parent: kuilt-3126
    summary: "Drafted, not filed. bee#19 waits on it."
    depends_on: [kuilt-3136, kuilt-3137]

  kuilt-3126-e:
    kind: kuilt
    title: "(e) Migration by re-seed, and a format tag"
    status: next
    parent: kuilt-3126
    summary: "Drafted, not filed."
    depends_on: [kuilt-3126-d]

  kuilt-3126-f:
    kind: kuilt
    title: "(f) Quilter frontier wiring (kuilt#2177)"
    status: next
    parent: kuilt-3126
    summary: "Drafted, not filed."
    depends_on: [kuilt-3126-d]

  kuilt-3126-g:
    kind: kuilt
    title: "(g) Writerside and sample rewrite, and the ORMap guard"
    status: next
    parent: kuilt-3126
    summary: "Drafted, not filed."
    depends_on: [kuilt-3126-d]

  kuilt-3133:
    kind: kuilt
    title: "kuilt-raft: prune a removed peer's replication state, and reset it at election"
    status: in-flight
    started: "2026-11-07T22:29Z"
    links:
      - { title: "kuilt#3133", url: "https://github.com/tractat-us/kuilt/pull/3133" }

  kuilt-3134:
    kind: kuilt
    title: "kuilt-raft: a node stops campaigning once its removal is committed"
    status: waiting-on-iain
    summary: "A spec-critical engine change that departs from the issue's suggested fix; needs Iain's review before merge."
    started: "2026-11-07T22:32Z"
    links:
      - { title: "kuilt#3134", url: "https://github.com/tractat-us/kuilt/pull/3134" }

  kuilt-3129:
    kind: kuilt
    title: "session: the RoomHost contract doesn't say whether onRoom ends when its connection tears"
    status: in-flight
    summary: "The tear signal bee needs to close a claims session when its learner leaves (bee#23). Slice 1, the conformance suite, is in review."
    started: "2026-11-08T01:28Z"
    links:
      - { title: "kuilt#3129", url: "https://github.com/tractat-us/kuilt/issues/3129" }
      - { title: "kuilt#3141, slice 1", url: "https://github.com/tractat-us/kuilt/pull/3141" }

  kuilt-3142:
    kind: kuilt
    title: "quilter: no signal that a replica has caught up with the peer it joined"
    status: next
    started: "2026-11-08T02:25Z"
    links:
      - { title: "kuilt#3142", url: "https://github.com/tractat-us/kuilt/issues/3142" }

  kuilt-3143:
    kind: kuilt
    title: "store: IndexedDbDurableStore lets synchronous JS throws escape as JsException, which no catch (Exception) sees"
    status: next
    summary: "Found in bee#39. bee works around it with a decorator, so it doesn't wait on the fix."
    started: "2026-11-08T02:41Z"
    links:
      - { title: "kuilt#3143", url: "https://github.com/tractat-us/kuilt/issues/3143" }

  kuilt-3144:
    kind: kuilt
    title: "Quilter drops a delta or FullState over the seam's payload budget without a word"
    status: next
    summary: "bee hit it on its board link in #38, and works around it with WireBudget for now."
    started: "2026-11-08T02:58Z"
    links:
      - { title: "kuilt#3144", url: "https://github.com/tractat-us/kuilt/issues/3144" }

  kuilt-3145:
    kind: kuilt
    title: "WebSocket installs take no frame bound, so one header can allocate 2 GiB"
    status: next
    summary: "Found in the review of bee#42. bee works around it in the host's socket gate, so it doesn't wait on the fix."
    started: "2026-11-08T03:25Z"
    links:
      - { title: "kuilt#3145", url: "https://github.com/tractat-us/kuilt/issues/3145" }

  kuilt-3146:
    kind: kuilt
    title: "Server looms accept a WebSocket handshake from any web page: no Origin or Host check"
    status: next
    summary: "bee checks Origin and Host itself since bee#51, so it doesn't wait on the fix."
    started: "2026-11-08T04:01Z"
    links:
      - { title: "kuilt#3146", url: "https://github.com/tractat-us/kuilt/issues/3146" }

  kuilt-own-write-ack:
    kind: kuilt
    title: "Quilter: a caller can't wait until its own write is acknowledged"
    status: next
    summary: "Quilter.mutate doesn't return its sequence number, so bee counts writes against universalAckFlow instead. Filed as kuilt#3147 and named in #38's KDoc."
    started: "2026-11-08T15:02Z"
    links:
      - { title: "kuilt#3147", url: "https://github.com/tractat-us/kuilt/issues/3147" }
      - { title: "bee#38", url: "https://github.com/tractat-us/bee/pull/38" }

  kuilt-3148:
    kind: kuilt
    title: "Star overlays: a spoke's Quilter can't sendTo another spoke, so a mid-stream joiner never heals its cursor"
    status: next
    summary: "A spoke that joins mid-stream sees another spoke's edits only at the next anti-entropy round."
    started: "2026-11-08T17:33Z"
    links:
      - { title: "kuilt#3148", url: "https://github.com/tractat-us/kuilt/issues/3148" }

  kuilt-3149:
    kind: kuilt
    title: "Relay: attest each record's author by the connection that first delivered it"
    status: next
    summary: "Behind bee#60 and bee#64; needed before a second person or a keyed agent attaches, and bee states the limit for v1."
    started: "2026-11-08T17:42Z"
    links:
      - { title: "kuilt#3149", url: "https://github.com/tractat-us/kuilt/issues/3149" }
      - { title: "bee#68", url: "https://github.com/tractat-us/bee/pull/68" }

  kuilt-3150:
    kind: kuilt
    title: "Move Ktor to 3.6.1: Netty and WebSocket drop a session's last frame on 3.5.2"
    status: next
    summary: "bee moved itself to 3.6.1 in #69, so it doesn't wait on this."
    started: "2026-11-08T18:00Z"
    links:
      - { title: "kuilt#3150", url: "https://github.com/tractat-us/kuilt/issues/3150" }

  # ── Outside the code ─────────────────────────────────────────────────
  bee-42-hand-check:
    kind: outside
    title: "Pair a real phone over the LAN"
    status: waiting-on-iain
    summary: "The e2e never binds off loopback, so mDNS, the macOS firewall, Wi-Fi isolation and mobile Safari or Chrome are unproven."
    started: "2026-11-08T17:26Z"
    links:
      - { title: "bee#42", url: "https://github.com/tractat-us/bee/pull/42" }
      - { title: "Steps: Showing the board on another screen", url: "../setup.md#showing-the-board-on-another-screen" }

  bee-auto-close:
    kind: outside
    title: "Turn off auto-close in bee's settings"
    status: waiting-on-iain
    summary: "Settings, General, Issues; a UI toggle only, to match the rest of tractat-us."
    started: "2026-11-08T17:26Z"
    links:
      - { title: "Ruling on bee#6", url: "https://github.com/tractat-us/bee/issues/6#issuecomment-6724665300" }

  out-cla:
    kind: outside
    title: "Contributor agreement text and a signing check"
    status: waiting-on-iain
    summary: "A lawyer writes it, not an agent. Needed before the repo accepts outside contributions."
    links:
      - { title: "Epic bee#6", url: "https://github.com/tractat-us/bee/issues/6" }

  out-kuilt-references:
    kind: outside
    title: "kuilt References policy: allow references to public tractat-us projects"
    status: later
    summary: "A kuilt AGENTS.md PR, landed once bee is public."
    links:
      - { title: "Epic bee#6", url: "https://github.com/tractat-us/bee/issues/6" }
```
