---
phase: 05-reliability-documentation
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
  - docs/user-guide/troubleshooting.md
  - docs/faq.md
autonomous: true
requirements: [DOCS-01]
must_haves:
  truths:
    - "A reader of docs/user-guide/troubleshooting.md finds a 'Gen4 Power-Save Wake Tail' section stating the sub-250 ms first-command wake tail on gen4 devices, when it matters (first command after idle), and what to do (optional periodic polling)"
    - "The wake-tail section identifies gen4 concretely: host firmware major version >= 4 via get_host_firmware(), shown as a code one-liner — no product-ID list"
    - "The wake-tail section contains a runnable polling recipe using get_color() on a 15-second cadence"
    - "A visible admonition callout states the library deliberately ships no keepalive daemon and why: zero idle-related loss was measured on healthy networks, so periodic polling is the application's choice"
    - "docs/faq.md contains an entry linking to user-guide/troubleshooting.md#gen4-power-save-wake-tail"
    - "troubleshooting.md no longer recommends a multi-pass discovery loop — it states that a single discover_devices() call already re-broadcasts on an escalating schedule within the discovery window"
    - "The discovery-timeout example in troubleshooting.md uses async-for iteration over discover() and states the actual 15.0 s default"
    - "The polling recipe is idempotent by construction: it uses a read-only request (get_color()) so running it twice — or continuously — has no side effects and stays far below the ~20 msg/sec device budget"
    - "The polling recipe documents concurrent operation: it runs alongside normal application traffic as a background task (asyncio.create_task() or TaskGroup) with no extra coordination, because the library serialises requests per connection"
  artifacts:
    - path: "docs/user-guide/troubleshooting.md"
      provides: "DOCS-01 wake-tail guidance + stale discovery/retry fixes"
      contains: "### Gen4 Power-Save Wake Tail"
    - path: "docs/faq.md"
      provides: "Short wake-tail FAQ entry (link-only, D5-01)"
      contains: "troubleshooting.md#gen4-power-save-wake-tail"
  key_links:
    - from: "docs/faq.md"
      to: "docs/user-guide/troubleshooting.md"
      via: "relative markdown link to the wake-tail heading anchor"
      pattern: "user-guide/troubleshooting\\.md#gen4-power-save-wake-tail"
    - from: "docs/user-guide/troubleshooting.md"
      to: "docs/user-guide/animation.md"
      via: "D5-02 cross-link where streaming meets gen4 power-save (page-level link; the streaming section anchor is created later by plan 05-02)"
      pattern: "\\(animation\\.md"
  prohibitions:
    - statement: "MUST NOT frame the gen4 wake tail as a reliability or packet-loss problem — Spike 001 measured zero idle-related loss; it is a bounded, latency-only effect (sub-250 ms) on gen4 devices only"
      category: transparency
      requirement_id: DOCS-01
    - statement: "MUST NOT present the unconfirmed power-save mechanism (ESP32 modem sleep) as fact, and MUST NOT extend wake-tail claims to mesh networks — scope all claims to healthy networks as measured"
      category: transparency
      requirement_id: DOCS-01
    - statement: "MUST NOT leak spike methodology, measurement narrative, or internal planning artefacts into the published docs — numbers yes, methodology no (D5-03; internal specs stay in .claude/)"
      category: privacy
      requirement_id: DOCS-01
---

<objective>
Document the gen4 power-save wake-tail behaviour (DOCS-01) on the existing
troubleshooting page with a link-only FAQ entry (D5-01), and fix that page's stale
pre-v1.1 discovery/retry advice in the same pass (D5-10 audit findings #5–#8).

This plan creates the `#gen4-power-save-wake-tail` anchor that plans 05-02 (animation
and ceiling-lights cross-links) depends on — the heading text is pinned and MUST be
written exactly as specified (Pitfall 1 in 05-RESEARCH.md: three pages link to it).

Purpose: a reader can find accurate wake-tail guidance — what happens (sub-250 ms
first-command latency after idle, gen4 only), when it matters, and what to do
(optional 10–15 s polling) — plus the explicit statement that the library deliberately
ships no keepalive daemon (D5-06).

Output: updated docs/user-guide/troubleshooting.md and docs/faq.md; docs build stays
clean (exit 0, no warning naming either edited page).

Decisions implemented: D5-01, D5-02 (outbound half), D5-03, D5-04, D5-05, D5-06, D5-10.
</objective>

<execution_context>
@$HOME/.claude/gsd-core/workflows/execute-plan.md
@$HOME/.claude/gsd-core/templates/summary.md
</execution_context>

<context>
@.planning/phases/05-reliability-documentation/05-CONTEXT.md
@.planning/phases/05-reliability-documentation/05-RESEARCH.md
@.planning/phases/05-reliability-documentation/05-PATTERNS.md
</context>

<assumption_delta_decision>
Noun: "wire-behaviour source phase" (detector signal: pluralization term "also" in the
ROADMAP dependency line "also draws on Phases 2–3 outcomes").
Decision: no-change — documentation naturally aggregates several already-shipped phases;
no singular architectural assumption is being pluralised and no identity noun loses a
monopoly. Advisory only; nothing to encode as an invariant.
</assumption_delta_decision>

<tasks>

<task type="auto">
  <name>Task 1: Add the Gen4 Power-Save Wake Tail section to troubleshooting.md</name>
  <files>docs/user-guide/troubleshooting.md</files>
  <read_first>
    - docs/user-guide/troubleshooting.md (current state; section template at lines 89–113: Symptom/Causes/Solution shape; TOC at lines 5–11)
    - .planning/phases/05-reliability-documentation/05-RESEARCH.md (§Verified Numbers — the only permitted source for figures; §Code Examples — polling recipe and gen4 one-liner shapes)
    - docs/user-guide/ceiling-lights.md lines 120–135 and 370–380 (the two in-repo admonition exemplars: `!!! note "Custom Title"` / `!!! tip "Custom Title"` with 4-space-indented body)
  </read_first>
  <action>
    Insert a new section into docs/user-guide/troubleshooting.md under the existing
    `## Performance Issues` heading (line 224), after the `### Slow Operations`
    section ends (~line 302) and before `### Docker / Container Networking`
    (line 304). The heading MUST be exactly `### Gen4 Power-Save Wake Tail` — the
    toc-generated anchor `#gen4-power-save-wake-tail` is linked from faq.md (Task 3
    of this plan), ceiling-lights.md and animation.md (plan 05-02). No TOC edit is
    needed: a `###` under the already-TOC'd `## Performance Issues` inherits it.

    Follow the page's Symptom/Causes/Solution section shape (D5-03: concise + key
    numbers, no measurement narrative). Content, per D5-03/D5-04/D5-05/D5-06 and the
    verified figures in 05-RESEARCH.md §Verified Numbers:

    - Symptom: the first command after a device has been idle (roughly a minute or
      more) is slower than usual — up to ~250 ms instead of single-digit
      milliseconds. Affects gen4 devices only; gen2/gen3 show no such tail. Zero
      packets are lost — this is latency, not reliability (prohibition: never frame
      as a loss/reliability problem). Scope claims to healthy networks; do not
      mention mesh networks or the suspected chipset mechanism.
    - Identifying gen4 (D5-05): host firmware major version 4 or later. Show the
      one-liner: `firmware = await device.get_host_firmware()` then
      `firmware.version_major >= 4` (inside `async with`, the cached
      `device.host_firmware` property is already populated). Do NOT enumerate
      product IDs — the products registry has no generation field.
    - What to do (D5-04): optional periodic state polling keeps the radio awake for
      latency-sensitive applications. Include the polling recipe from 05-RESEARCH.md
      §Code Examples verbatim in shape: a `keep_awake(light)` async function calling
      `await light.get_color()` then `await asyncio.sleep(15)`, with the comment
      that 10–15 s keeps the wake tail away and that `get_color()` returns colour,
      power and label in a single request/response pair. State that it runs
      alongside the application via `asyncio.create_task()` or `asyncio.TaskGroup`
      with no extra coordination — the library serialises requests per connection.
      The recipe is read-only and stays far below the ~20 msg/sec device budget.
    - D5-06 admonition (visible callout, not an inline sentence), matching the
      ceiling-lights.md convention (`!!! note "Custom Title"`, 4-space-indented
      body). Title names the fact, e.g. "lifx-async deliberately ships no keepalive
      daemon". Body must include the why: measured on real hardware, idle devices
      lose zero packets on healthy networks — the wake tail is a small, bounded
      latency cost, not a reliability problem; whether to spend a packet every
      10–15 seconds is the application's choice, so the library does not make it.
    - D5-02 cross-link: end the section with a sentence linking to the Animation
      Guide (page-level relative link `(animation.md)`) for streaming consumers —
      where sustained streaming meets gen4 power-save. Do NOT use a heading anchor
      into animation.md (its streaming section is created later by plan 05-02).

    Australian English throughout. The troubleshooting page uses device-layer
    examples — no HSBK/colour construction appears in the recipe at all (Pitfall 4).
  </action>
  <verify>
    <automated>grep -q '^### Gen4 Power-Save Wake Tail' docs/user-guide/troubleshooting.md && grep -q 'version_major >= 4' docs/user-guide/troubleshooting.md && grep -q 'asyncio.sleep(15)' docs/user-guide/troubleshooting.md && grep -qE '!!! (note|info) "' docs/user-guide/troubleshooting.md && uv run zensical build</automated>
  </verify>
  <acceptance_criteria>
    - `grep -c '^### Gen4 Power-Save Wake Tail' docs/user-guide/troubleshooting.md` outputs 1 (exact heading — anchor stability)
    - Section body contains `250` (the sub-250 ms bound) and `version_major >= 4` (gen4 identification one-liner)
    - Polling recipe present: `grep -q 'get_color()' docs/user-guide/troubleshooting.md` and `grep -q 'asyncio.sleep(15)' docs/user-guide/troubleshooting.md` both succeed; recipe mentions `create_task` or `TaskGroup`
    - Admonition present: a `!!! note "..."` or `!!! info "..."` line with a custom title exists in the new section, body indented 4 spaces, containing the zero-idle-loss rationale
    - `grep -c 'keepalive daemon' docs/user-guide/troubleshooting.md` outputs >= 1
    - D5-02 link present: `grep -qE '\(animation\.md\)' docs/user-guide/troubleshooting.md` succeeds
    - `grep -ci 'spike' docs/user-guide/troubleshooting.md` outputs 0 (no methodology narrative leaks — D5-03)
    - `grep -ci 'mesh' docs/user-guide/troubleshooting.md` outputs 0 and `grep -ci 'ESP32' docs/user-guide/troubleshooting.md` outputs 0 (claims scoped to healthy networks; mechanism omitted)
    - `uv run zensical build` exits 0; `uv run zensical build 2>&1 | grep -i warning | grep -c 'troubleshooting'` outputs 0
  </acceptance_criteria>
  <done>The wake-tail section exists with the pinned heading, verified numbers, gen4 one-liner, 15 s polling recipe, visible no-keepalive admonition, and animation-guide link; docs build clean.</done>
</task>

<task type="auto">
  <name>Task 2: Fix stale discovery/retry advice in troubleshooting.md (audit #5–#8)</name>
  <files>docs/user-guide/troubleshooting.md</files>
  <read_first>
    - docs/user-guide/troubleshooting.md (sections: "Partial Device Discovery" lines 89–113; "Connection Drops" lines 152–185; "Discovery Timeout Too Short" lines 210–223; correct async-for usage exemplar at lines 49–57)
    - .planning/phases/05-reliability-documentation/05-RESEARCH.md (§Stale-Content Audit Findings items #5–#8; §State of the Art table)
    - src/lifx/const.py line 28 (DISCOVERY_TIMEOUT = 15.0 — the true default)
  </read_first>
  <action>
    Three in-place fixes, per audit findings #5–#8 (D5-10 — fix contradictions in
    place, no new pages or sections):

    1. "Partial Device Discovery" (lines 89–113): the Solution currently shows a
       manual multi-pass discovery loop. Superseded by DISC-01 (Phase 2): a single
       `discover_devices()` call now re-broadcasts `GetService` on an escalating
       schedule within the discovery window. Replace the multi-pass recipe with a
       short Solution stating that one call already re-broadcasts internally, and
       that increasing `timeout` is the right lever for slow or congested networks.
       Keep the Symptom/Causes framing; keep legitimate causes (different subnets,
       AP client isolation) intact.

    2. "Discovery Timeout Too Short" (lines 210–223): the example on line 220 wraps
       discovery in an async context manager — a pre-existing API misuse, since
       `discover()` is an async generator. Rewrite the example to the async-for
       iteration shape used at lines 49–57 of this same page (passing
       `timeout=10.0`). In the same edit, correct the stale inline comment about the
       default: the actual default is 15.0 s (`DISCOVERY_TIMEOUT`,
       src/lifx/const.py:28).

    3. "Connection Drops" (lines 152–185): contextualise, don't delete (RESEARCH
       open question 2). The app-level retry wrapper remains legitimate for
       whole-operation failures; add one or two sentences noting that since v1.1 the
       library itself retransmits within each request's timeout (floored first
       window, escalating gaps, wall-time honoured — RETRY-01..04), so wrappers are
       for whole-operation failures, not per-packet reliability. Do not name
       internal constants or schedule shapes beyond that behavioural statement.

    Australian English. No other sections on the page change in this task.
  </action>
  <verify>
    <automated>! grep -q 'async with discover(' docs/user-guide/troubleshooting.md && ! grep -q 'Default is 3.0' docs/user-guide/troubleshooting.md && grep -qi 're-broadcast' docs/user-guide/troubleshooting.md && uv run zensical build</automated>
  </verify>
  <acceptance_criteria>
    - `grep -c 'async with discover(' docs/user-guide/troubleshooting.md` outputs 0 (API misuse gone)
    - `grep -c 'Default is 3.0' docs/user-guide/troubleshooting.md` outputs 0 and `grep -q '15.0' docs/user-guide/troubleshooting.md` succeeds (stale default corrected)
    - `grep -qi 're-broadcast' docs/user-guide/troubleshooting.md` succeeds (Partial Device Discovery now states the DISC-01 behaviour)
    - The Partial Device Discovery Solution no longer contains a loop that calls discovery multiple times (no `for`/`while` + discovery-call combination remains within that section, lines ~89–113 region)
    - Connection Drops section still contains its retry-wrapper example AND a sentence noting the library already retransmits within each request's timeout
    - `uv run zensical build` exits 0; `uv run zensical build 2>&1 | grep -i warning | grep -c 'troubleshooting'` outputs 0
  </acceptance_criteria>
  <done>Audit items #5–#8 fixed in place: no multi-pass discovery recipe, correct discover() usage with the 15.0 s default, contextualised (not deleted) retry-wrapper guidance; build clean.</done>
</task>

<task type="auto">
  <name>Task 3: Add the wake-tail FAQ entry (link-only) to faq.md</name>
  <files>docs/faq.md</files>
  <read_first>
    - docs/faq.md (structure: `## Category` / `### Question`; `## Performance` at line 185; `## Troubleshooting` at line 240; "Why can't discovery find my devices?" at lines 47–61)
    - .planning/phases/05-reliability-documentation/05-PATTERNS.md (faq.md conventions; link path shape from docs root: `user-guide/troubleshooting.md#<anchor>`)
  </read_first>
  <action>
    Two small additions per D5-01 and audit #14/#15:

    1. Add ONE new `### <question>` entry under the existing `## Performance`
       category (a single combined entry covering both the wake tail and
       why-no-keepalive is preferred — one entry or two is discretionary, but keep
       it short). Question wording is discretionary (e.g. asking why the first
       command after idle is slower on newer devices). Body: 2–4 sentences — gen4
       devices add a sub-250 ms wake tail to the first command after idle; zero
       packets are lost; the library deliberately ships no keepalive daemon because
       polling is the application's choice; link to the full guidance at
       `user-guide/troubleshooting.md#gen4-power-save-wake-tail` (relative path from
       docs root — faq.md sits beside the user-guide directory).

    2. Audit #14 (minor, optional-but-do-it): in "Why can't discovery find my
       devices?" (lines 47–61), add one sentence noting that a single discovery call
       already re-broadcasts automatically on an escalating schedule, so increasing
       `timeout` — not calling discovery repeatedly — is the right fix.

    Australian English. No other entries change.
  </action>
  <verify>
    <automated>grep -q 'user-guide/troubleshooting.md#gen4-power-save-wake-tail' docs/faq.md && uv run zensical build</automated>
  </verify>
  <acceptance_criteria>
    - `grep -c 'user-guide/troubleshooting.md#gen4-power-save-wake-tail' docs/faq.md` outputs >= 1
    - The new entry is a `###` heading under `## Performance` (between lines 185 and the next `##`)
    - New entry body mentions the sub-250 ms bound (contains `250`) and the absence of a keepalive daemon
    - The discovery FAQ entry (lines 47–61 region) mentions automatic re-broadcast
    - `uv run zensical build` exits 0; `uv run zensical build 2>&1 | grep -i warning | grep -cE '(faq|troubleshooting)'` outputs 0 (the anchor resolves — no broken-anchor warning)
  </acceptance_criteria>
  <done>FAQ links to the wake-tail anchor and the discovery entry reflects DISC-01; build clean with no anchor warnings.</done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| published docs → reader behaviour | Guidance shapes what application developers build against real devices |
| internal planning artefacts → public site | .planning/ and .claude/ content must not leak into published docs |

## STRIDE Threat Register

| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|-----------|----------|-----------|----------|-------------|-----------------|
| T-05-01 | Information Disclosure | docs/user-guide/troubleshooting.md, docs/faq.md | low | mitigate | D5-03 forbids methodology narrative; prohibition + `grep -ci 'spike'` gate keeps internal spike/planning content out of published pages |
| T-05-02 | Denial of Service | polling recipe (reader-side device flooding) | low | mitigate | Recipe pinned to 15 s cadence (10–15 s range) — far below the ~20 msg/sec device limit; gate asserts `asyncio.sleep(15)` |
| T-05-SC | Tampering | npm/pip/cargo installs | low | accept | No package-manager installs occur in this phase (RESEARCH §Package Legitimacy Audit: none) |
</threat_model>

<verification>
- `uv run zensical build` exits 0 after every task; no warning line names troubleshooting.md or faq.md (warning total stays at the pre-edit baseline — RESEARCH.md records 8, all in docs/api/ pages this phase never edits)
- Wake-tail anchor resolves from faq.md (no new "anchor does not exist" warnings)
- All figures in the new content trace to 05-RESEARCH.md §Verified Numbers — no invented numbers (D5-04/D5-05)
- mkdocs.yml is unchanged (D5-01: no new nav entries): `git diff --name-only` does not list mkdocs.yml
- docs/changelog.md, docs/api/*.md, and source files are unchanged
</verification>

<success_criteria>
- DOCS-01 satisfied: wake-tail behaviour documented (sub-250 ms, when polling helps, gen4 identification, no-keepalive admonition) on the troubleshooting page with a FAQ link
- Audit findings #5–#8 fixed in place; no multi-pass discovery workaround remains on the page
- Docs build cleanly with the new content (phase success criterion 3, this plan's pages)
</success_criteria>

## Artifacts this phase produces (this plan's share)

- New heading/anchor: `docs/user-guide/troubleshooting.md` → `### Gen4 Power-Save Wake Tail` (`#gen4-power-save-wake-tail`) — the anchor plans 05-02 links against
- New FAQ entry heading (wording discretionary) under `## Performance` in `docs/faq.md`
- Modified files: `docs/user-guide/troubleshooting.md`, `docs/faq.md`
- No code symbols, no new pages, no nav entries

<output>
Create `.planning/phases/05-reliability-documentation/05-01-SUMMARY.md` when done.
Record in the summary: the exact wake-tail heading/anchor as written (downstream plans link to it), and confirmation that no figure was invented (each traced to 05-RESEARCH.md §Verified Numbers).
</output>
