Product OS
TL;DRaudit · 2026-08-19

No audit has written a summary yet. The audit writes this part, so it stays empty until one does.

What a machine did without youClosed 1 task, unconfirmed. Below.
Tell it what changedany chat
What this doesHands a new chat everything this page believes, including what it could not prove, and asks what actually happened. Everything below this line is as of the last audit until you run it.
The prompt
You are updating Product OS.

Read https://raw.githubusercontent.com/hooterjackson/product-os/main/public/llms.txt and follow it.

WHAT IT BELIEVES RIGHT NOW — 6 projects, 19 open tasks. Everything below is as of the last audit.

engineering-site — live at engineering.engineered.lighting; stale in both directions.
  Nothing open.

gimbal-bench — M5 fault ring layers one and two measured; Zigbee parked (D15).
  Last worked 19 Aug.
  17 open, top 3:
    GB-001  Finish the M5 fault ring: a real fault storm, and the brownout case
    GB-014  Un-park Zigbee — the decision D15 leaves open
    GB-005  Prepare the radio build: memory layout, and a stub for signing updates (Z-M1)
    (14 more in this project not listed here — ask if you need them)

home-ai-infra — provisioned; credential hygiene outstanding.
  No repository, so its status is my word only.
  1 open:
    HAI-001  Rotate the GPU box's Linux password

home-app — one squashed snapshot; no usable timeline.
  1 open:
    APP-001  Give HomeApp an evidence rule that does not depend on git history

product-os — slice 1a-minus.
  Nothing open.

robotic-spotlight — bench proven; LED head unordered.
  Nothing open.

CLOSED BY A MACHINE, NEVER CONFIRMED BY ME — 1:
  EL-004  Update every document that still names the old motor (EL-004 · RMD-L-4005 → 5005)

Tell me what actually happened since 2026-08-19. Then hand back:
  1. status changes, each with the SHA or path that proves it
  2. candidates you derived, each with its evidence
  3. for each project I mentioned: one plain sentence on where it now stands,
     in my words where I gave them, and a new `phase` line if it changed

Anything you cannot prove, say so and leave it open. Do not close a task I have not confirmed.
Where to paste itAny chat window, including this phone. The prompt carries no path — it reads the repo over the web, so nothing needs to be cloned.
What happens nextIt answers with status changes, derived candidates and a new TL;DR. From a chat you carry the answer back; from the Mac it writes them itself. Either way this page shows them the next time it is built.
Backlog
gimbal-benchlast worked 19 Aug · 17 open
What it isFirmware and a commissioning bench that can prove, from a record, that the fixture stays a light.
Where it isM5 fault ring layers one and two measured; Zigbee parked (D15)
Last sessionWrote this item's return path by hand. `state/threads/manual.yaml` now carries a `GB-004:` line pointing at the web chat that ran the bench work. That chat has no transcript on disk, so `tools/index.py` was never going to find it — it is the first entry the file has ever held.
17 open
GB-001Finish the M5 fault ring: a real fault storm, and the brownout caseCopyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-034 · Any flash or NVS write on a fault path**No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
R-035 · Restoring the fault ring from flash whenever flash has a copy`mirrorRestore()` returns immediately **unless layer one came back empty**.
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-040 · Tombstoning `spot-bench.yaml` wholesaleThe file names exactly what survives D3:
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-001 in your first message.

# GB-001 — Finish the M5 fault ring: a real fault storm, and the brownout case

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**This is the next thing built, and the ruling says so in its own words.** The fault ring (M5) needs nothing from any of them, and it is the next thing built. — D15, `owner-decisions-20260814.md` Layers one and two exist and are measured (`ring-first-read-20260814.md` `c02b507`, `ring-mirror-20260814.md` `669a3a7`, both 2026-08-14). Layer one found three real defects within an hour of existing — *"none of them visible in the live serial log"*. What is left is the list the mirror capture writes down about itself:

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-034 · Any flash or NVS write on a fault path**
  **No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
- **R-035 · Restoring the fault ring from flash whenever flash has a copy**
  `mirrorRestore()` returns immediately **unless layer one came back empty**.
- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-040 · Tombstoning `spot-bench.yaml` wholesale**
  The file names exactly what survives D3:

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-001`.

## Decisions in force

- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-001=<SHA> --status GB-001=done \ --said "your sentence"
Tied togimbal-bench · GB-001
GB-014Un-park Zigbee — the decision D15 leaves openCopyneeds the repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 3
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-042 · `esp-zigbee-lib` enums in the Z-M0 mailboxThe mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-014 in your first message.

# GB-014 — Un-park Zigbee — the decision D15 leaves open

gimbal-bench · next · gate external
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**This is a decision, not a task, and it has not been taken.** It exists as a node because of what the graph said without it. With `GB-001` pointing straight at `GB-005`, the chain read *finish the fault ring → Z-M1*, which invites exactly one wrong inference: that completing the fault ring un-parks Zigbee automatically. It does not. Something has to happen between them that no agent can do, and a chain that hides an unmade decision is worse than one that shows it.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-042 · `esp-zigbee-lib` enums in the Z-M0 mailbox**
  The mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Gate `external`: this needs hardware or a person that may not be present.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-014`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · needs the repoThis task is worked in gimbal-bench. Whether the machine you are reading this on has a clone is not something a published page can know, so no command is offered — run it where the repo is.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-014=<SHA> --status GB-014=done \ --said "your sentence"
Tied togimbal-bench · GB-014
GB-005Prepare the radio build: memory layout, and a stub for signing updates (Z-M1)Copyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-027 · R2 in the "c-boot" sub-formRuled, then overturned by adversarial review **the same day**:
R-028 · Secure boot (`CONFIG_SECURE_BOOT_V2`) — rejected for now, not foreverHardware-capable and genuinely stronger — it protects the bootloader too. Rejected because:
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-005 in your first message.

# GB-005 — Prepare the radio build: memory layout, and a stub for signing updates (Z-M1)

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Z-M1** | **Variant + partitions + signing scaffold** — `GIMBAL_ZIGBEE` dependent flag + compound suffix + `#error` + the 7th mega_gate leg (flight image); `zigbee_zczr`; the c-patch build-time signer + the verify-before-handoff scaffold. **No Zigbee code yet.**

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-027 · R2 in the "c-boot" sub-form**
  Ruled, then overturned by adversarial review **the same day**:
- **R-028 · Secure boot (`CONFIG_SECURE_BOOT_V2`) — rejected for now, not forever**
  Hardware-capable and genuinely stronger — it protects the bootloader too. Rejected because:
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-005`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-005=<SHA> --status GB-005=done \ --said "your sentence"
Tied togimbal-bench · GB-005
GB-006Add the single-slot mailbox the radio and the safety loop pass messages through (Z-M0)Copyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 3
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-042 · `esp-zigbee-lib` enums in the Z-M0 mailboxThe mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-006 in your first message.

# GB-006 — Add the single-slot mailbox the radio and the safety loop pass messages through (Z-M0)

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Z-M0** | **The §9.1 mailbox primitive** — single-slot coalesce-to-latest admission record using **primitive types (uint16/uint8), not esp-zigbee-lib enums** [§10 hole 4], so it compiles ahead of the library; the always-honored stop latch bypassing + purging the slot; a fake producer.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-042 · `esp-zigbee-lib` enums in the Z-M0 mailbox**
  The mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-006`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-006=<SHA> --status GB-006=done \ --said "your sentence"
Tied togimbal-bench · GB-006
GB-008Bring the fixture up on the radio and prove it still behaves like a light (Z-M3)Copyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 3
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-042 · `esp-zigbee-lib` enums in the Z-M0 mailboxThe mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-008 in your first message.

# GB-008 — Bring the fixture up on the radio and prove it still behaves like a light (Z-M3)

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Z-M3** | **Zigbee bring-up AS A LIGHT** — router join (`zczr`), on/off/level clusters, the APSDE filter (stage-E record, TC source-bind), telemetry shell. Greenfield bulk. The fan-out point: §6 states *"Z-M4/Z-M5/Z-M6 on Z-M3"*, which is where three of this chain's four leaves attach.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-042 · `esp-zigbee-lib` enums in the Z-M0 mailbox**
  The mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-008`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-008=<SHA> --status GB-008=done \ --said "your sentence"
Tied togimbal-bench · GB-008
GB-002Rescue D1-D11 off formd-t1 and commit themCopyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 3
R-026 · Reading a pre-2026-08-13 wire capture without asking whether the tap was openAn open tap changes three things at once: TX succeeds, the error counters drain (*"CAN error counters fall only on a successful transmission"*), and canonical SAFE becomes reachable on a …
R-038 · Reading "no head-dropping observed" as "the head does not drop"The first map on 2026-08-15 was genuinely good — five tilt poses, released 5-minute windows, *"**the head does not fall anywhere**"*, worst case 0.62° one-time settle and 0.01°/min creep. …
R-066 · Two agents writing one working treeThe multi-machine design makes **cross-machine** conflict structurally impossible: `state/threads/by-machine/<id>.json` is written by exactly one machine's indexer, so two machines syncing …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-002 in your first message.

# GB-002 — Rescue D1-D11 off formd-t1 and commit them

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Eleven owner rulings exist in exactly one place, and it is not a repository.** D12-D16 are safe: full prose, committed, `e4d71a9`. D1-D11 are not. They survive only as one-line digests in a section headed: # 5. Owner decisions — D1 through D15 exist in §4; D16 exists only by reference; no D17–D20

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-026 · Reading a pre-2026-08-13 wire capture without asking whether the tap was open**
  An open tap changes three things at once: TX succeeds, the error counters drain (*"CAN error counters fall only on a successful transmission"*), and canonical SAFE becomes reachable on a …
- **R-038 · Reading "no head-dropping observed" as "the head does not drop"**
  The first map on 2026-08-15 was genuinely good — five tilt poses, released 5-minute windows, *"**the head does not fall anywhere**"*, worst case 0.62° one-time settle and 0.01°/min creep. …
- **R-066 · Two agents writing one working tree**
  The multi-machine design makes **cross-machine** conflict structurally impossible: `state/threads/by-machine/<id>.json` is written by exactly one machine's indexer, so two machines syncing …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-002`.

## Decisions in force

- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-002=<SHA> --status GB-002=done \ --said "your sentence"
Tied togimbal-bench · GB-002
Q-001Does Spot Mode (Auto/Hold/Manual) survive gate A?Copyneeds the repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-030 · Relying on the motors' own comm timeout as the safety netIt exists and it is a real backstop, but it removes power. On a brakeless gravity axis that risks a drop rather than a hold.
R-032 · A flat `0x81` pin for the mute entry-stop opcodeRejected along with a second writer for `kaLastTxOk`. The chosen mechanism selects from the mute's own live evidence: ACKed solicits → the motor likely heard → hold (`0x81`); un-ACKed → …
R-038 · Reading "no head-dropping observed" as "the head does not drop"The first map on 2026-08-15 was genuinely good — five tilt poses, released 5-minute windows, *"**the head does not fall anywhere**"*, worst case 0.62° one-time settle and 0.01°/min creep. …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite Q-001 in your first message.

# Q-001 — Does Spot Mode (Auto/Hold/Manual) survive gate A?

gimbal-bench · next · gate none
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**This is a question, not a task, and the source is explicit that it is unruled:** `Spot Mode` (Auto/Hold/Manual) → a gate-A product question (no deployed-profile analog under D12 — re-derive or retire) The tension it sits in is real and both halves are sourced:

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-030 · Relying on the motors' own comm timeout as the safety net**
  It exists and it is a real backstop, but it removes power. On a brakeless gravity axis that risks a drop rather than a hold.
- **R-032 · A flat `0x81` pin for the mute entry-stop opcode**
  Rejected along with a second writer for `kaLastTxOk`. The chosen mechanism selects from the mute's own live evidence: ACKed solicits → the motor likely heard → hold (`0x81`); un-ACKed → …
- **R-038 · Reading "no head-dropping observed" as "the head does not drop"**
  The first map on 2026-08-15 was genuinely good — five tilt poses, released 5-minute windows, *"**the head does not fall anywhere**"*, worst case 0.62° one-time settle and 0.01°/min creep. …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py Q-001`.

## Decisions in force

- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · needs the repoThis task is worked in gimbal-bench. Whether the machine you are reading this on has a clone is not something a published page can know, so no command is offered — run it where the repo is.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence Q-001=<SHA> --status Q-001=done \ --said "your sentence"
Tied togimbal-bench · Q-001
GB-004M6 on hardware: the motor-silent limb, MUTE-CLEAR, and the armed laneCopyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-055 · Proving the armed-lane mute by physically unplugging a connectorThe drill is self-defeating and the capture works out why:
R-031 · Auto-disarm on the ACKed half of an armed muteThree reasons, all recorded: killing a two-axis session for a one-axis fault that disarm cannot cure buys nothing the degrade does not; at the archived 2-minute cadence auto-disarm makes …
R-032 · A flat `0x81` pin for the mute entry-stop opcodeRejected along with a second writer for `kaLastTxOk`. The chosen mechanism selects from the mute's own live evidence: ACKed solicits → the motor likely heard → hold (`0x81`); un-ACKed → …
R-033 · A third mute causeNo archived slow-motor regime exists, and the RX-CORRELATION-ERROR lines already discriminate the shape on the wire. Same family as F3's rejection of a new READY blocker: `reply_stale` …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-004 in your first message.

# GB-004 — M6 on hardware: the motor-silent limb, MUTE-CLEAR, and the armed lane

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

M6's mute machinery landed and flashed on 2026-08-15. One limb is proven live: proven live: `MUTE cause=bus-no-ack` at 2.3 s from boot and the same paragraph names what is not:

## Where it stands

Evidence on file: 19dd790, 34b9f7c, 1525192, 7f5b060.
Next, from the last handoff: unchanged — the dev-gated reply-drop drill on the `+mutesim` image, as

## Already ruled out — read before proposing anything

- **R-055 · Proving the armed-lane mute by physically unplugging a connector**
  The drill is self-defeating and the capture works out why:
- **R-031 · Auto-disarm on the ACKed half of an armed mute**
  Three reasons, all recorded: killing a two-axis session for a one-axis fault that disarm cannot cure buys nothing the degrade does not; at the archived 2-minute cadence auto-disarm makes …
- **R-032 · A flat `0x81` pin for the mute entry-stop opcode**
  Rejected along with a second writer for `kaLastTxOk`. The chosen mechanism selects from the mute's own live evidence: ACKed solicits → the motor likely heard → hold (`0x81`); un-ACKed → …
- **R-033 · A third mute cause**
  No archived slow-motor regime exists, and the RX-CORRELATION-ERROR lines already discriminate the shape on the wire. Same family as F3's rejection of a new READY blocker: `reply_stale` …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-004`.

## Decisions in force

- **DEC-016** (D16) — The M6 armed-mute forks, settled by adoption
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-004=<SHA> --status GB-004=done \ --said "your sentence"
Tied togimbal-bench · GB-004
Q-002Does a mid-move retarget re-plan smoothly, or stop and restart?Copyneeds the repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-018 · "Caliper the 5005 for a raised boss on the output face"### 1. Is there a raised boss on the output face? — **NO.**
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-030 · Relying on the motors' own comm timeout as the safety netIt exists and it is a real backstop, but it removes power. On a brakeless gravity axis that risks a drop rather than a hold.
R-064 · Measuring a proxy instead of measuring the tool's output`PROP-0003` proposed twenty `done` items and claimed they would drop group D from **301 to 13**. **The real effect is zero**, and the proposal was queued for a one-sentence yes.
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite Q-002 in your first message.

# Q-002 — Does a mid-move retarget re-plan smoothly, or stop and restart?

gimbal-bench · next · gate none
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

D12 settles the safety half and leaves this open, and states plainly that it is **a measurement rather than an argument**: If the motor re-plans its curve smoothly on a new `0xA4` that arrives before deceleration, a follow looks like a Broadway spotlight. If it stops and restarts, it looks like a stuttering security camera.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-018 · "Caliper the 5005 for a raised boss on the output face"**
  ### 1. Is there a raised boss on the output face? — **NO.**
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-030 · Relying on the motors' own comm timeout as the safety net**
  It exists and it is a real backstop, but it removes power. On a brakeless gravity axis that risks a drop rather than a hold.
- **R-064 · Measuring a proxy instead of measuring the tool's output**
  `PROP-0003` proposed twenty `done` items and claimed they would drop group D from **301 to 13**. **The real effect is zero**, and the proposal was queued for a one-sentence yes.

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py Q-002`.

## Decisions in force

- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · needs the repoThis task is worked in gimbal-bench. Whether the machine you are reading this on has a clone is not something a published page can know, so no command is offered — run it where the repo is.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence Q-002=<SHA> --status Q-002=done \ --said "your sentence"
Tied togimbal-bench · Q-002
Q-003Does a brownout preserve the RTC domain?Copyneeds the repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 3
R-035 · Restoring the fault ring from flash whenever flash has a copy`mirrorRestore()` returns immediately **unless layer one came back empty**.
R-034 · Any flash or NVS write on a fault path**No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite Q-003 in your first message.

# Q-003 — Does a brownout preserve the RTC domain?

gimbal-bench · next · gate none
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**The brownout case**, unknown in both directions. A brownout may or may not preserve the RTC domain, and nothing here has produced one. The M5 ring distinguishes "the fixture rebooted itself" from "somebody cut the power" using three agreeing signals — reset reason, `lost` flag, and whether the flash mirror had to be restored. A brownout is the case that table has no row for, and a ceiling fixture on household mains will meet one.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-035 · Restoring the fault ring from flash whenever flash has a copy**
  `mirrorRestore()` returns immediately **unless layer one came back empty**.
- **R-034 · Any flash or NVS write on a fault path**
  **No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py Q-003`.

## Decisions in force

- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · needs the repoThis task is worked in gimbal-bench. Whether the machine you are reading this on has a clone is not something a published page can know, so no command is offered — run it where the repo is.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence Q-003=<SHA> --status Q-003=done \ --said "your sentence"
Tied togimbal-bench · Q-003
GB-007Build the rollback ladder, so a bad radio update can be backed out (Z-M2)Copyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-027 · R2 in the "c-boot" sub-formRuled, then overturned by adversarial review **the same day**:
R-028 · Secure boot (`CONFIG_SECURE_BOOT_V2`) — rejected for now, not foreverHardware-capable and genuinely stronger — it protects the bootloader too. Rejected because:
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-007 in your first message.

# GB-007 — Build the rollback ladder, so a bad radio update can be backed out (Z-M2)

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Z-M2** | **The rollback ladder (§8 — D15's ruled first radio commit)** — `verifyRollbackLater()→true`; mark-valid strictly on {`zigbeeJoined`, `twaiReady`, N iterations, no panic} (NOT readyBlocker terms); `ota_reboot_expected`; `joinWasWorking`; park-before-opt-in; **the c-patch signature check runs in the OUTGOING image before handoff**

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-027 · R2 in the "c-boot" sub-form**
  Ruled, then overturned by adversarial review **the same day**:
- **R-028 · Secure boot (`CONFIG_SECURE_BOOT_V2`) — rejected for now, not forever**
  Hardware-capable and genuinely stronger — it protects the bootloader too. Rejected because:
- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-007`.

## Decisions in force

- **DEC-101** (R2) — R2 = c-patch: the outgoing image verifies the new one before handoff
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-007=<SHA> --status GB-007=done \ --said "your sentence"
Tied togimbal-bench · GB-007
GB-012Gate L — the fixture joins and holds as a lightCopyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-023 · Carrying stage 1's 2.0 A supply limit into stage 6Stage 1 sets 2.0 A for the LED-only stages and the draft never raised it again. At stage 6 the motors join the same rail with 21 tape channels lit:
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-042 · `esp-zigbee-lib` enums in the Z-M0 mailboxThe mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-012 in your first message.

# GB-012 — Gate L — the fixture joins and holds as a light

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Gate L MET = the fixture joins and holds as a light** (needs the LED path, §5). The radio-live owner session. Two prerequisites are stated by §5 and are modelled as confirmed edges into this item: **Two owner/BoM prerequisites for gate L** [§10 hole 8]: the **LED photometric path** (GPIO10/11/18 ledc — "join as a light" cannot be demonstrated as a *light* without it; today compile-only), and the **HA-side Zigbee OTA server** (Z2M/ZHA OTA provider + image index + the signer→server pipeline — the OTA drill presupposes it).

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-023 · Carrying stage 1's 2.0 A supply limit into stage 6**
  Stage 1 sets 2.0 A for the LED-only stages and the draft never raised it again. At stage 6 the motors join the same rail with 21 tape channels lit:
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-042 · `esp-zigbee-lib` enums in the Z-M0 mailbox**
  The mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-012`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-012=<SHA> --status GB-012=done \ --said "your sentence"
Tied togimbal-bench · GB-012
GB-013Stand up the HA-side Zigbee OTA serverCopyneeds the repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-027 · R2 in the "c-boot" sub-formRuled, then overturned by adversarial review **the same day**:
R-028 · Secure boot (`CONFIG_SECURE_BOOT_V2`) — rejected for now, not foreverHardware-capable and genuinely stronger — it protects the bootloader too. Rejected because:
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-013 in your first message.

# GB-013 — Stand up the HA-side Zigbee OTA server

gimbal-bench · next · gate none
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

The second of §5's two stated gate-L prerequisites: the **HA-side Zigbee OTA server** (Z2M/ZHA OTA provider + image index + the signer→server pipeline — the OTA drill presupposes it) `gate: none` and no `machine_affinity`: this is Home Assistant-side work, not bench work, and the HA install already exists. It is the one item in the Zigbee neighbourhood that can genuinely be started without `formd-t1`.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-027 · R2 in the "c-boot" sub-form**
  Ruled, then overturned by adversarial review **the same day**:
- **R-028 · Secure boot (`CONFIG_SECURE_BOOT_V2`) — rejected for now, not forever**
  Hardware-capable and genuinely stronger — it protects the bootloader too. Rejected because:
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-013`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · needs the repoThis task is worked in gimbal-bench. Whether the machine you are reading this on has a clone is not something a published page can know, so no command is offered — run it where the repo is.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-013=<SHA> --status GB-013=done \ --said "your sentence"
Tied togimbal-bench · GB-013
Q-004Where do 300 liveness taps a second come from?Copyneeds the repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-036 · Quieting the firmware's logging first when chasing the serial floodQuieting the firmware first would hide the browser bug under a lower volume rather than fixing it.
R-025 · Listen-only mode on the CANable `candleLight` tap**It has no working listen-only mode** — the repo verified this directly: `L` is unimplemented and silent mode is doubly broken.
R-026 · Reading a pre-2026-08-13 wire capture without asking whether the tap was openAn open tap changes three things at once: TX succeeds, the error counters drain (*"CAN error counters fall only on a successful transmission"*), and canonical SAFE becomes reachable on a …
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite Q-004 in your first message.

# Q-004 — Where do 300 liveness taps a second come from?

gimbal-bench · next · gate none
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

The liveness tap should go about 5 times a second. Something sends it about **300**, which jams the cable so the genuine tap cannot get through, so the fixture concludes the operator has vanished and disarms. Nobody knows where 300/s comes from. Every known sender caps around 30/s even degraded, so something is retrying in a tight loop and it has never been found.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-036 · Quieting the firmware's logging first when chasing the serial flood**
  Quieting the firmware first would hide the browser bug under a lower volume rather than fixing it.
- **R-025 · Listen-only mode on the CANable `candleLight` tap**
  **It has no working listen-only mode** — the repo verified this directly: `L` is unimplemented and silent mode is doubly broken.
- **R-026 · Reading a pre-2026-08-13 wire capture without asking whether the tap was open**
  An open tap changes three things at once: TX succeeds, the error counters drain (*"CAN error counters fall only on a successful transmission"*), and canonical SAFE becomes reachable on a …
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py Q-004`.

## Decisions in force

- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included
- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · needs the repoThis task is worked in gimbal-bench. Whether the machine you are reading this on has a clone is not something a published page can know, so no command is offered — run it where the repo is.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence Q-004=<SHA> --status Q-004=done \ --said "your sentence"
Tied togimbal-bench · Q-004
GB-009Decide how the fixture is commissioned, and what a reset actually resets (Z-M4)Copyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-034 · Any flash or NVS write on a fault path**No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
R-042 · `esp-zigbee-lib` enums in the Z-M0 mailboxThe mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-009 in your first message.

# GB-009 — Decide how the fixture is commissioned, and what a reset actually resets (Z-M4)

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Z-M4** | **Commissioning gesture + reset-call** — power-on-only counter in app-NVS, breadcrumbs, confirm-blink; the F-A5 reset-call choice explicit. A leaf of the chain, on Z-M3 per §6. The residual fork F-A5 (which reset call) is listed in §2 as inherited and unresolved, which is why `confidence` is proposed at 3 rather than 4.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-034 · Any flash or NVS write on a fault path**
  **No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
- **R-042 · `esp-zigbee-lib` enums in the Z-M0 mailbox**
  The mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-009`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-009=<SHA> --status GB-009=done \ --said "your sentence"
Tied togimbal-bench · GB-009
GB-010Prove the deployed fixture only moves when it is meant to (Z-M5)Copyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 3
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-042 · `esp-zigbee-lib` enums in the Z-M0 mailboxThe mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-010 in your first message.

# GB-010 — Prove the deployed fixture only moves when it is meant to (Z-M5)

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Z-M5** | **The deployed §4.1 motion predicate + `command_unauthenticated`** — realize the authority §4.1 predicate as the deployed+zigbee gate…; the new cause through the **atomic** four-link chain; `ota_in_progress` gets its OWN chain.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-042 · `esp-zigbee-lib` enums in the Z-M0 mailbox**
  The mailbox uses **primitive types (uint16/uint8), not esp-zigbee-lib enums**, so it compiles ahead of the library. Using the library's enums couples the milestone to a dependency the …

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-010`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-010=<SHA> --status GB-010=done \ --said "your sentence"
Tied togimbal-bench · GB-010
GB-011Report telemetry over the radio, including the long dumps (Z-M6)Copyon formd-t1
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-039 · Un-parking Zigbee before the fault ring and the drills**Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
R-029 · Replacing the dead-man with a hub-sourced liveness timerOver Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
R-034 · Any flash or NVS write on a fault path**No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
R-035 · Restoring the fault ring from flash whenever flash has a copy`mirrorRestore()` returns immediately **unless layer one came back empty**.
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite GB-011 in your first message.

# GB-011 — Report telemetry over the radio, including the long dumps (Z-M6)

gimbal-bench · next · gate none · machine formd-t1
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

Firmware and a commissioning bench that can prove, from a record, that the fixture stays a light.

## What this is

**Z-M6** | **Telemetry attributes + chunked dump over Zigbee** — the §9 attribute set + RTC-ring dump; `snapshotSeq`. The remote read of the M5 fault ring — which is the thing D15 says is missing today: Every recovery behaviour added on 2026-08-14 is currently observable only by somebody watching a serial port — which is the one state a deployed fixture is never in.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-039 · Un-parking Zigbee before the fault ring and the drills**
  **Zigbee is ruled (D3) and parked (D15). Not dead, not next.** Both halves matter; either one alone gets the priority wrong in an opposite direction.
- **R-029 · Replacing the dead-man with a hub-sourced liveness timer**
  Over Zigbee a brief dropout takes **seconds** to recover, not milliseconds, so a 400 ms timer would trip constantly on a healthy system. Loosening it to seconds means seconds of uncommanded …
- **R-034 · Any flash or NVS write on a fault path**
  **No fault path touches flash.** An NVS commit erases a page and can block for tens of milliseconds; the stop budget is 50 ms and does not negotiate.
- **R-035 · Restoring the fault ring from flash whenever flash has a copy**
  `mirrorRestore()` returns immediately **unless layer one came back empty**.

## Work here, not in product-os

Repo: `gimbal-bench`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.
Machine: **formd-t1**. If that is not where you are, the honest answer is "resume on formd-t1" — not a plan you cannot execute.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py GB-011`.

## Decisions in force

- **DEC-015** (D15) — Zigbee stays parked until the fault ring and the drills are done
- **DEC-003** (D3) — Transport is Zigbee, C6 as router, light included

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · on formd-t1This task is bound to formd-t1. Whether that is the machine you are reading this on is not something a published page can know, so no command is offered.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence GB-011=<SHA> --status GB-011=done \ --said "your sentence"
Tied togimbal-bench · GB-011
1 chat
Fix stale product-os entry in state/repos.jsonclaude-code · work-laptop · last active 19 AugRESUME
What it wasThe `product-os` entry in `state/repos.json` contradicted an accepted decision record, and this fixed the entry to match the ruling. · also touches engineering-site, home-ai-infra, home-app, product-os, robotic-spotlight
What it touchedAPP-001 — Give HomeApp an evidence rule that does not depend on git historyEL-001 — Order the Doc 4 LED BoMEL-002 — The bench meter has no current rangeEL-003 — Print the tolerance coupon, then the fit coupon+46 more
Which projectPlaced by the tasks it cites, not by you. Say so and your word wins.Say which project→
The way backThis chat lives on work-laptop. Run this there — it prints the resume command for every chat worth returning to. The command itself is machine-local, so this page cannot print it.
On work-laptopCopy
cd ~/Claude/product-os python3 tools/index.py --ways-back
Why this verdictlast active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
home-ai-infra1 open
What it isA GPU box the perception stack can be built on without ceremony.
Where it isprovisioned; credential hygiene outstanding
No repositoryNothing here can be verified from commits, so its status changes only when you say so. Not stale — unauditable.
Last sessionA handoff has not been written yet. Absent is not the same as nothing happened.
1 open
HAI-001Rotate the GPU box's Linux passwordCopyno repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled outNothing matches this task's keywords. That is not the same as nothing having been ruled out — this section is empty, not clear.
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite HAI-001 in your first message.

# HAI-001 — Rotate the GPU box's Linux password

home-ai-infra · next · gate none
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

A GPU box the perception stack can be built on without ceremony.

## What this is

The handoff file for the GPU box says, as step 2 of its SSH setup: **Rotate your Linux password** (`passwd` on the box) — it was shared in the chat session on the work computer. — `~/Claude/PICKUP.md:19` That file is dated **2026-06-09**. Today is 2026-08-19.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

NOTHING in wiki/ruled-out.md matches this item's keywords. That is not the same as nothing having been ruled out — this section is empty, not clear.

## Work here, not in product-os

**`home-ai-infra` has no repository.** Nothing about this task can be verified from commits, so its status changes only when Marcelo says so. Do not report it as stale, and do not close it on anything but his word or a dated note.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py HAI-001`.

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · no repohome-ai-infra has no repository. Nothing here can be verified from commits, so its status changes only when Marcelo says so.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence HAI-001=<SHA> --status HAI-001=done \ --said "your sentence"
Tied tohome-ai-infra · HAI-001
home-app1 open
What it isThe household's own front end to the house.
Where it isone squashed snapshot; no usable timeline
Last sessionA handoff has not been written yet. Absent is not the same as nothing happened.
1 open
APP-001Give HomeApp an evidence rule that does not depend on git historyCopyneeds the repo
What this doesHands a chat this task, what has already been ruled out for it, and how stale that knowledge is.
Already ruled out · 4
R-044 · Seeding or auditing from a local clone$ git rev-list --count HEAD..origin/main # in the local clone 0 $ gh api .../compare/90ff98d...main --jq .ahead_by 54
R-037 · Proving mute machinery offlineM6's first-hour P1 was invisible to
R-053 · Paraphrasing inside quotation marksA plan shipped a composite quote that existed nowhere — inside a section headed *"edges the evidence states, quoted."*
R-056 · Browser-local state as a repo evidence rule`EL-001`'s evidence rule named `docs/bom-checklist.md` and nothing else. That file says of itself:
The promptlast audit 2026-08-19 · 153 commits unattributed then
Cite APP-001 in your first message.

# APP-001 — Give HomeApp an evidence rule that does not depend on git history

home-app · next · gate none
Freshness: last audit 2026-08-19 · 153 commits unattributed then

## Project context

The household's own front end to the house.

## What this is

`hooterjackson/HomeApp` is **one commit**: `b769b30`, 2026-06-12T15:05Z, "Deploy current Home app snapshot". I verified this against the remote — the whole `main` history is that single entry. Every commit-shaped evidence query against this repo therefore returns nothing, forever, and **nothing is not the same as no work happened.** Left alone, this project would quietly report "clean" in every audit while being the one place the system genuinely cannot see.

## Where it stands

No evidence recorded. It cannot be closed until something can be clicked.
Next, from the last handoff: NO HANDOFF RECORDED — nobody wrote down where this was left.

## Already ruled out — read before proposing anything

- **R-044 · Seeding or auditing from a local clone**
  $ git rev-list --count HEAD..origin/main # in the local clone 0 $ gh api .../compare/90ff98d...main --jq .ahead_by 54
- **R-037 · Proving mute machinery offline**
  M6's first-hour P1 was invisible to
- **R-053 · Paraphrasing inside quotation marks**
  A plan shipped a composite quote that existed nowhere — inside a section headed *"edges the evidence states, quoted."*
- **R-056 · Browser-local state as a repo evidence rule**
  `EL-001`'s evidence rule named `docs/bom-checklist.md` and nothing else. That file says of itself:

## Work here, not in product-os

Repo: `HomeApp`. product-os TRACKS the work; it does not host it. Make the change there and come back only to write the handoff.

## Chats already working on this

- claude-code · work-laptop · Fix stale product-os entry in state/repos.js
  RESUME — last active 2026-08-19; could NOT check whether work landed in its repo — resume, but re-read the brief first
  A verified way back exists on work-laptop, but it names that machine's paths and the session id, so it is not republished. In your product-os clone THERE, run `python3 tools/kickoff.py APP-001`.

## Rules

- Nothing is done without evidence — a commit SHA, a file path, or a
  dated note. If you cannot produce one, it is not done. Say so.
- Say "I couldn't look", never "no changes". An empty result and an
  unreachable repo are different facts.
- Do not write his decided fields: project, gate, machine_affinity,
  parked/dropped, or the evidence rule. Draft into state/drafts/
  instead — never straight into the task.
- Do not reorder state/backlog.md. That file is his judgement, and it
  is the only order there is. Say so once if you disagree, then work
  on what he put at the top.
Machine · needs the repoThis task is worked in HomeApp. Whether the machine you are reading this on has a clone is not something a published page can know, so no command is offered — run it where the repo is.
What happens nextThe chat works in the repo the task names and writes a handoff when it stops. Nothing here changes until the next audit reads that.
Close itDone needs something you can click — a SHA, a path, a dated note. Dropping needs only a reason.It is donedoneWon't dodropcd <your product-os clone> python3 tools/apply.py --evidence APP-001=<SHA> --status APP-001=done \ --said "your sentence"
Tied tohome-app · APP-001
engineering-sitenothing open
What it isThe published eight-document build series stays true to what the bench actually did.
Where it islive at engineering.engineered.lighting; stale in both directions
Last sessionA handoff has not been written yet. Absent is not the same as nothing happened.
Nothing openNothing open. 4 set aside.
1 chat
Engineered Lighting MkDocs site buildclaude-code · work-laptop · last active 29 JulRESTART
What it wasBuilding engineering.engineered.lighting: turning the seven-document Engineered Lighting research series into an MkDocs site.
What it touchedCites no task — it will not appear on any of them.
Which projectPlaced by the tasks it cites, not by you. Say so and your word wins.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-07-29; engineered-lighting-site has commits after that, so its model of the repo is provably behind and the brief is not
product-osnothing open
What it isKnow what to work on next, and never be told progress that cannot be clicked.
Where it isslice 1a-minus
Last sessionA handoff has not been written yet. Absent is not the same as nothing happened.
Nothing openNothing open. Not idle by accident — there is simply nothing here.
4 chats
Tool rebuild around refined modelclaude-code · work-laptop · last active 23 AugRESUME
What it wasRebuilding product-os around a refined model — deleting the scoring engine and dependency graph, and turning the tool into a read-only dashboard whose product is copyable prompts.
What it touchedPOS-001 — Build product-os slice 1a-minus (archived)POS-002 — Point PROJECT-STATE.md at product-os (archived)POS-003 — Build /audit: re-check priorities against reality (archived)POS-004 — apply.py: distinguish who decided, not just what changed (archived)+8 more
Which projectPlaced by the tasks it cites, not by you. Say so and your word wins.Say which project→
The way backThis chat lives on work-laptop. Run this there — it prints the resume command for every chat worth returning to. The command itself is machine-local, so this page cannot print it.
On work-laptopCopy
cd ~/Claude/product-os python3 tools/index.py --ways-back
Why this verdictlast active 2026-08-23, and nothing has landed in product-os since
BOOTSTRAP.md setup planclaude-code · work-laptop · last active 23 AugRESTART
What it wasThe original build, straight from BOOTSTRAP.md — planned first, then written. 134 exchanges, and most of what this repo now is came out of it.
What it touchedPOS-001 — Build product-os slice 1a-minus (archived)POS-002 — Point PROJECT-STATE.md at product-os (archived)POS-003 — Build /audit: re-check priorities against reality (archived)POS-004 — apply.py: distinguish who decided, not just what changed (archived)+8 more
Which projectPlaced by the tasks it cites, not by you. Say so and your word wins.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdict134 prompts — long enough that its early context is noise
Product-OS slice 1a-minus seedclaude-code · work-laptop · last active 19 AugRESUME
What it wasContinuing the slice 1a-minus build under a stop hook that kept the session on POS-001.
What it touchedPOS-001 — Build product-os slice 1a-minus (archived)POS-002 — Point PROJECT-STATE.md at product-os (archived)POS-003 — Build /audit: re-check priorities against reality (archived)POS-004 — apply.py: distinguish who decided, not just what changed (archived)+8 more
Which projectPlaced by the tasks it cites, not by you. Say so and your word wins.Say which project→
The way backThis chat lives on work-laptop. Run this there — it prints the resume command for every chat worth returning to. The command itself is machine-local, so this page cannot print it.
On work-laptopCopy
cd ~/Claude/product-os python3 tools/index.py --ways-back
Why this verdictlast active 2026-08-19, and nothing has landed in product-os since
Product-OS slice 1a-minus buildclaude-code · work-laptop · last active 19 AugRESUME
What it wasOne sitting on 2026-08-19 · 1 exchange · on `main` · no description written yet
What it touchedPOS-001 — Build product-os slice 1a-minus (archived)
Which projectPlaced by the tasks it cites, not by you. Say so and your word wins.Say which project→
The way backThis chat lives on work-laptop. Run this there — it prints the resume command for every chat worth returning to. The command itself is machine-local, so this page cannot print it.
On work-laptopCopy
cd ~/Claude/product-os python3 tools/index.py --ways-back
Why this verdictlast active 2026-08-19, and nothing has landed in product-os since
robotic-spotlightnothing open
What it isA silent, high-CRI pan/tilt head on CAN servos that behaves like an ordinary light and can also aim itself.
Where it isbench proven; LED head unordered
Last sessionA handoff has not been written yet. Absent is not the same as nothing happened.
Nothing openNothing open. A machine closed EL-004 here without you — below. 3 set aside.
Add a taskbacklog
Don't let me forget thisinbox
It asks nothing, because every question is a reason not to bother next time.
Closed without you · 1

A machine decided these were finished. You have confirmed none of them. Each is its own call — five separate judgements, not one, because batching them would turn five decisions into one shrug.

EL-004Update every document that still names the old motor (EL-004 · RMD-L-4005 → 5005)
What it claimsClosed 2026-07-21 · evidence 8fb39bf, db41f3f
Your way out — either one, from anywhereIt was rightconfirmIt was not — reopen itreopen
Or from a terminalcd <your product-os clone> python3 tools/apply.py --decided EL-004=status:done \ --said "your sentence here"Same command with status:next reopens it. The sentence is required — without it the change is only proposed.
Chats with no project · 7

6 chats sit with their projects above; 2 hidden as not this portfolio.

These cite no task, so nothing can place them. One tap each, and they stop being a list you scroll past.

Project planning and chat organization toolclaude-code · work-laptop · last active 18 AugRESTART
What it wasIdeating the tool that became product-os — how the hardware site, the chats, and the priorities could stop being three separate places.
What it touchedCites no task — it will not appear on any of them.
Which projectNothing can derive this — it cites no task. Say once, and it survives re-indexing.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-08-18; engineered-lighting-site has commits after that, so its model of the repo is provably behind and the brief is not
Implement guided recoverycodex · work-laptop · last active 3 AugRESTART
What it wasPicking up the genio handoff — implementing its guidance and governance layer from a written spec.
What it touchedCites no task — it will not appear on any of them.
Which projectNothing can derive this — it cites no task. Say once, and it survives re-indexing.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-08-03, more than 7 days before this index ran
Plan Apple Music playlist toolcodex · work-laptop · last active 22 JulRESTART
What it wasBuilding a tool to turn a ChatGPT-researched list of Paulinho da Costa credits into an Apple Music playlist.
What it touchedCites no task — it will not appear on any of them.
Which projectNothing can derive this — it cites no task. Say once, and it survives re-indexing.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-07-22, more than 7 days before this index ran
Confirm smart home contextcodex · work-laptop · last active 21 JulRESTART
What it wasRe-establishing what the smart home setup actually is, as context for later work.
What it touchedCites no task — it will not appear on any of them.
Which projectNothing can derive this — it cites no task. Say once, and it survives re-indexing.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-07-21, more than 7 days before this index ran
Compare Parallels alternativescodex · work-laptop · last active 20 JulRESTART
What it wasComparing Parallels against the other ways of running Windows on a Mac.
What it touchedCites no task — it will not appear on any of them.
Which projectNothing can derive this — it cites no task. Say once, and it survives re-indexing.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-07-20, more than 7 days before this index ran
Plan Paulinho playlist toolcodex · work-laptop · last active 13 JulRESTART
What it wasThe first pass at the Paulinho da Costa playlist tool, before the Apple Music side was worked out.
What it touchedCites no task — it will not appear on any of them.
Which projectNothing can derive this — it cites no task. Say once, and it survives re-indexing.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-07-13, more than 7 days before this index ran
V-JEPA 2.1 home context trainingclaude-code · work-laptop · last active 10 JunRESTART
What it wasTraining V-JEPA 2.1 to recognise household context — reading, cooking, working out — with pose detection, on the RTX 6000 box.
What it touchedCites no task — it will not appear on any of them.
Which projectNothing can derive this — it cites no task. Say once, and it survives re-indexing.Say which project→
The way backStart a new chat. Its context is behind the repo, so there is nothing to return to — copy the task's kickoff prompt instead.
Why this verdictlast active 2026-06-10, more than 7 days before this index ran

This page reads. It never writes — every action leaves through a chat or a GitHub issue under your own sign-in, and it holds no token.