Extends Phase 6's identity rather than adding a service — all of this is facts
about who someone is, already identity's job.
- admin.html/admin.js: manage people/guests, edit every field, prune, history,
access log. Deliberately not kiosk-shaped and not linked from any wall panel —
a panel anyone can walk up to shouldn't carry a "prune these people" button.
- Nicknames are an input alias only. /resolve accepts them; every payload also
carries speak_name (always the real name) and chores/ uses it for reminders.
A nickname colliding with anyone's name or nickname is refused; a spoken string
matching two people refuses with ambiguous_name rather than picking one.
- Visit history sampled from identity's own /presence. home:null writes nothing,
ever — an HA outage must not record a departure that didn't happen. Departures
need sustained absence (BLE flaps) and are stamped at the last time actually
seen. "With whom" is an interval-overlap query, not a second table.
- Pruning splits selecting from deleting: the filter fills the checkboxes, the
delete goes by explicit id, and the filter is never re-run at delete time.
- Device rights are an answer, never an action — identity stores grants and
answers GET /device-access; HA asks and HA acts. Deny is the default and the
only fallback. Grants can expire; every check is logged, denials included.
- Chore assignment prefers an assignee who's home but doesn't let an absent one
block the chore (CHORE_ASSIGNMENT_STRICT flips that). Litter still ignores
both exemption and assignment.
- Admin-added identifiers still enforce TRUSTED_ENTITY_PREFIXES; only the
"in range right now" check is relaxed, never the allowlist.
Resolves open decision #26; adds #34-37 for the new unknowns (DEPARTURE_GRACE_
SECONDS is untuned, the panel has never been opened in a browser).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phase 19: trash-calendar (Kennelbach ICS -> CalDAV) and transit (GTFS
departures + OpenTripPlanner-backed voice route planning, slow walking
speed assumed). Phase 20: Tapo camera integration via identity's new
Frigate face-recognition presence signal, and chores, a presence/
calendar-driven household task nudger ("I don't care who does it, as
long as it gets done") with a passive fairness tally, litter culprit
attribution, and per-person chore_exempt/chore_reminder_style settings
on identity.
Also: the HA integrations + hardware-monitoring catalogs, Music
Assistant wiring, docs/network-integration.md (OPNsense VLAN
segmentation, no WAN port-forwards), the ESPHome BLE-proxy firmware,
and RuView CSI-presence integration (github.com/ruvnet/ruview) with
household automations for sleep/distress/concurrent-vitals/bathroom-
occupancy — all flagged with their real unverified assumptions and
open decisions. Fixed two real port collisions surfaced while wiring
this in (OTP vs. zigbee2mqtt on 8080, Music Assistant vs. pantry-vision
on 8095).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6CrKjW3yVptUnjG35HjC1
identity/ (Phase 6, rewritten from the original Node-RED sketch): a
person <-> BLE-identifier registry built directly as a Python service.
Solves multi-phone (multiple identifiers per person), anti-spoofing
(only allowlisted IRK-resolved/fixed-tag entities are ever accepted as
registration candidates, never a raw or randomized MAC), device-less
people (a grandmother without a smartphone gets a no_device registration
plus a hand-operated home/away toggle, reported as "unknown" rather than
a false "away"), and anonymous guests (POST /register/guest, no name
needed). Every person gets an automatic profile picture from their most
recent registration photo. /presence also reports a best-effort room per
person as groundwork for an eventual floor-plan view (not built).
Registration is single-utterance voice ("register me as <name>") or a
touchscreen form; ambiguous/conflicting candidates never auto-commit.
hosts/door-panel/ (Phase 18, new host): structurally kitchen-display's
twin - one Sway workspace, one Chromium kiosk window - defaulting to
identity's weather+clothing/who's-home/groceries-running-low dashboard,
with voice registration as its actual purpose (mic on by default, unlike
every other host's opt-in).
hosts/kitchen-display/: adds opt-in voice satellite and a "Show
registration" screen pointed at identity's register.html, reusing the
same camera-equipped-endpoint registration flow.
pantry-vision/: adds GET /shopping-list (Grocy's own volatile/missing
products, reshaped) for the door panel's "running low" section.
setup-container-host.sh: wires ENABLE_IDENTITY (identity + identity-web,
published like pantry-vision since kiosk browsers call it directly, plus
a persistent SQLite/photos volume unlike pantry-vision's stateless
design) and fixes the HA_URL example to the host's real LAN IP (HA runs
network_mode: host, unreachable by container name - the same situation
Node-RED's own config already documents).
docs/: Phase 6 rewritten, Phase 18 added, hardware/software/guardrail/
open-decision entries throughout project-plan.md and README.md.
components.md gains RuView presence nodes (one per room), fixed BLE tags,
and 2 spare webcams, with the price estimate updated to match.
Nothing here has been run against real hardware, a real HA instance, or
real Private BLE Device entities - TRUSTED_ENTITY_PREFIXES above all
needs checking against a live instance before registration finds
anything. See identity/README.md and hosts/door-panel/README.md for the
itemized verification lists.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6CrKjW3yVptUnjG35HjC1