Host page "Operator Actions" card: run off-site backup now, run a check now
(fixed job list), stop / extend (1-30 days) a deletion countdown. POST
/hosts/{id}/operator-action validates against the CLOSED list before
storing (unknown -> 400, no row), stores operator_actions(id, customer_id,
action, arg, requested_at, requested_by, done_at, outcome, message), logs
who pressed (channel + address) and bumps the box's intent. The report ACK
lists pending rows as operator_actions until the box's
operator_action_results closes them (matched on id AND reporting
customer); each closed row becomes a hub-minted operator_action event
(stored, never dispatched). Unanswered after 24 h: expired. A customer
RESET cancels pending rows. Wire gate: new root + field-by-field mirror
(controller report.OperatorAction) — needs the controller commit first.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
Slice 1: intent.Hub records one start/end per GET /api/v1/wait request and answers
Presence(customer, now): connected (hold open, or one started < 333 s = 243 s cadence + 90 s
grace ago), not connected since T, or unknown (hub up < 333 s; in memory only). The host page
shows "Box connection". One DEBUG line per presence change.
Slice 2 (operator ruling D2, 2026-10-08, 09 §3 decision 186): a host that is online by its report
clock but whose box has had no wait-channel connection for >= 360 s may be deleted at once after
the tick "I checked: the box is off". Presence is re-read at POST time; the tick alone, unknown
presence, a connected box or a shorter gap keep today's 409. The delete logs the operator channel
and saves one host_deleted_box_off event. RESET and the customer-delete cascade are unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
On create and edit, a non-empty cf_api_token is checked with Cloudflare (GET /zones): it is saved only when
the token sees exactly one zone and the customer's domain is that zone or a name under it. More zones, another
zone, no zone, or Cloudflare not answering -> the form re-renders with one sentence and nothing is saved (the
previous token stays). An unchanged token on an unchanged domain and an empty token (HTTP-01) make no call.
The token is never logged and never in a sentence or error. Tests use a fake Cloudflare (httptest).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
On a pinned tier (the hub holds a CONFIRMED append-only key) the only
legitimate fall of the box's snapshot count is a clean-up window the hub
opened. The checker now compares prev - cur with what the windows closed
since the previous trustworthy report removed (store.RemovedByWindowsBetween,
2 h slack for the in-run count lag); any unexplained fall, even one snapshot,
raises offsite_snapshots_dropped (error) saying 'outside any clean-up window
the hub opened'. A window that cannot say what it removed (timeout, still
open) explains anything: no alarm, one INFO line. Non-pinned tiers keep the
half-rule. Untrustworthy reports: unchanged (no alarm, baseline kept).
Red tests: r435_pinned_drop_test.go (3 fail with the pinned rule disabled;
WindowExplainsFall fails when windows are ignored), r435_windows_between_test.go.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
The customer mail of health_degraded / health_critical / health_recovered no longer
appends the raw details JSON (frozen wire text, English or Hungarian whatever the
household's language). It says where to read the details: the dashboard. The
operator mail keeps the note; every other event keeps its note.
Red tests: r79_health_mail_test.go (2 failed on the old templates.go). Goldens
regenerated for the six health mails.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
Mealie, Homebox, Dawarich, Komga, Radicale, Recipe Importer (SVG) and SparkyFitness (PNG) are white now
(operator request), checked rendered in headless Chrome. crafty/grampsweb/homeassistant/plantit/uptimekuma
-> crafty-controller/gramps-web/home-assistant/plant-it/uptime-kuma, so the dashboard finds them (it asks
for <slug>-logo.*); both apps pages updated. R-912 filed (no gate checks this). Register 134 -> 135.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
Register 131 -> 134 (R-909 Apps card header, fixed on main; R-910 retake the website's dashboard pictures
after tomorrow's release; R-911 storage-unavailable banner stays Hungarian on English pages).
Evidence: before (0.303.0) / after (0.304.0-layout.rc2) pictures and measurements on scratch 9202, red proofs,
fixture diff. 9202 is back on 0.303.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
KernelDue / KernelNotify (09-20 h Budapest, one per 20 h, max 3, registered
address, only an accepted mail counts) / os_update.kernel {kver, tonight}
(no mail, no step) / layer kernel ingest + operator events / Approve kernel
set after every ring-0 box booted it healthily after a night stage / two
System page cells. 11 §5.11 written; §5.10 status corrected (proven).
Installer uninstall knows the two GRUB generators (unreleased).
Evidence: audits/kernel-lane-2026-10-07/ (red-proofs, boot timing).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS