summaryrefslogtreecommitdiff
path: root/prompts
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-07-18 12:06:15 +0300
committerPaul Buetow <paul@buetow.org>2026-07-18 12:06:15 +0300
commit5af64c1c60a00beffdd96a32f93889e71af44b6c (patch)
treedcff9fe863d3644496357060bd2e40fcef4334d8 /prompts
parent7b1d45c00105a09a247164f9cdbfebecb4de4b09 (diff)
update prompts
Diffstat (limited to 'prompts')
-rw-r--r--prompts/skills/f3s/references/bootstrap-netbsd-pi.md27
-rw-r--r--prompts/skills/f3s/references/goprecords-uptimed.md41
-rw-r--r--prompts/skills/f3s/references/pihole-pi.md4
3 files changed, 69 insertions, 3 deletions
diff --git a/prompts/skills/f3s/references/bootstrap-netbsd-pi.md b/prompts/skills/f3s/references/bootstrap-netbsd-pi.md
index e16e86f..44d4b58 100644
--- a/prompts/skills/f3s/references/bootstrap-netbsd-pi.md
+++ b/prompts/skills/f3s/references/bootstrap-netbsd-pi.md
@@ -212,11 +212,38 @@ Write a custom `/etc/rc.d/uptimed` (upstream ships a Linux-init `etc/rc.uptimed`
not usable directly):
```sh
+# PROVIDE: uptimed
+# REQUIRE: NETWORKING ntpdate
+# KEYWORD: shutdown
+
command="/usr/pkg/sbin/uptimed"
pidfile="/var/run/uptimed.pid"
command_args="-p ${pidfile}"
```
+These Raspberry Pis have no hardware RTC. NetBSD initializes the wall clock
+from the root filesystem timestamp, which can be stale after power-off. Merely
+starting `ntpd` is not a synchronization barrier, so enable the synchronous
+boot-time correction in `/etc/rc.conf`:
+
+```sh
+ntpdate=YES
+```
+
+The explicit `ntpdate` requirement above ensures that uptimed starts only after
+the clock has been set from the network. Verify the boot ordering with:
+
+```sh
+/sbin/rcorder /etc/rc.d/* | egrep '/(NETWORKING|ntpdate|ntpd|uptimed)$'
+```
+
+The expected order is `NETWORKING`, `ntpdate`, `ntpd`, then `uptimed`. This was
+deployed and reboot-tested one node at a time on both pi0 and pi1 on
+**2026-07-16**. `ntpdate` corrected pi0 by 12.29 seconds and pi1 by 12.68
+seconds before uptimed started; their new current records had the correct boot
+times, both webservers returned HTTP 200, and no historical record repair was
+necessary.
+
Run `uptimed -b` once (creates the boot ID), enable with `uptimed=YES`.
## goprecords upload
diff --git a/prompts/skills/f3s/references/goprecords-uptimed.md b/prompts/skills/f3s/references/goprecords-uptimed.md
index bf2c4ee..01d609c 100644
--- a/prompts/skills/f3s/references/goprecords-uptimed.md
+++ b/prompts/skills/f3s/references/goprecords-uptimed.md
@@ -17,7 +17,7 @@ The **`HOSTNAME`** in the URL must match the name passed to **`--create-client-k
- **`f0.lan` is not a hostname** (it will not resolve). Use the **full** name **`f0.lan.buetow.org`**, or the **LAN IP** from the f3s table (**`192.168.1.130`** for **f0**, **`.131`–`.133`** for **f1**–**f3**).
- **FreeBSD Beelinks and Pis:** **`ssh -p 22 paul@…`** (default SSH port). Your **`~/.ssh/config`** may use **port 2** for **OpenBSD frontends** only — that does **not** apply to **f0**–**f3** or **pi0**–**pi3**.
- **Pis:** **`pi0.lan.buetow.org`** … **`pi3.lan.buetow.org`** (full FQDN), port **22**.
-- **Manual upload test over SSH:** Beelinks use **`doas env GOPRECORDS_HOST=fN /usr/local/bin/goprecords-upload-client.sh`** (not **`sudo`** — often absent). Pis use **`sudo env GOPRECORDS_HOST=piN …`**.
+- **Manual upload test over SSH:** Beelinks use **`doas env GOPRECORDS_HOST=fN /usr/local/bin/goprecords-upload-client.sh`** (not **`sudo`** — often absent). Rocky Pis use **`sudo env GOPRECORDS_HOST=piN …`**. NetBSD Pis use **`doas env PATH=/usr/pkg/bin:/usr/bin:/bin:/usr/sbin:/sbin GOPRECORDS_HOST=piN /usr/pkg/bin/goprecords-upload-client.sh`**; the explicit path is required so the script can find pkgsrc `curl` and `uprecords` under `doas`.
## Where it is documented in-repo
@@ -35,8 +35,8 @@ Install **`curl`** and **`uptimed`** on every client that uploads.
|--------|--------|------------|--------|
| OpenBSD frontends | **fishfinger**, **blowfish** | **Rex** **`goprecords_upload`** in **`~/git/conf/frontends`**; **`/etc/daily.local`** runs **`/usr/local/bin/goprecords-upload.sh`** once per **day** | Tokens in **geheim** **`secrets/etc/goprecords/<host>.token`**; template **`scripts/goprecords-upload.sh.tpl`** |
| FreeBSD (Beelinks) | **f0**–**f3** (LAN **`192.168.1.130`–`133`**) | Manual **hourly** **root** **`cron`** calling **`goprecords-upload-client.sh`** with **`GOPRECORDS_HOST=f0`** … **`f3`** | **`/var/db/uptimed/records`**; SSH: **`fN.lan.buetow.org`** or **`192.168.1.(130+N)`** for **fN**, **`-p 22`** |
-| Raspberry Pi (Rocky) | **pi2**–**pi3** | Manual **hourly** **systemd** **timer** (see README) | **`/var/spool/uptimed/records`**; SSH: **`piN.lan.buetow.org`**, **`-p 22`** |
-| Raspberry Pi (NetBSD) | **pi0**–**pi1** | Manual **hourly** **root** **`cron`** (no systemd) calling **`goprecords-upload-client.sh`** with **`GOPRECORDS_HOST=pi0`**/**`pi1`** | **`/var/spool/uptimed/records`** (uptimed built from source — no prebuilt aarch64 pkgsrc package); SSH: **`piN.lan.buetow.org`**, **`-p 22`** |
+| Raspberry Pi (Rocky) | **pi2**–**pi3** | Manual **hourly** **systemd** **timer** (see README) | **`/var/spool/uptimed/records`**; uptimed waits for chronyd via a systemd override (see below); SSH: **`piN.lan.buetow.org`**, **`-p 22`** |
+| Raspberry Pi (NetBSD) | **pi0**–**pi1** | Manual **hourly** **root** **`cron`** (no systemd) calling **`goprecords-upload-client.sh`** with **`GOPRECORDS_HOST=pi0`**/**`pi1`** | **`/var/spool/uptimed/records`**; `ntpdate=YES` and uptimed requires the `ntpdate` rc.d milestone; see [NetBSD Pi setup](bootstrap-netbsd-pi.md#uptimed-built-from-source--no-prebuilt-package); SSH: **`piN.lan.buetow.org`**, **`-p 22`** |
| Fedora laptop | **earth** | **user** **systemd** **`oneshot` + hourly timer** `goprecords-upload-earth.{service,timer}` | Service sets **`Environment=GOPRECORDS_HOST=earth`** and runs **`~/.local/bin/goprecords-upload-earth.sh`**; token **`~/.config/goprecords-upload-earth/token`** |
| Mac (uptimed) → published by earth | **mega-m3-pro** (raw host `MBDVXJ4XKH9C`) | Mac drops records into the **worktime** git repo; **earth** pushes them via a **second `ExecStart`** in `goprecords-upload-earth.service` | See [Mac / mega-m3-pro via earth](#mac--mega-m3-pro-via-earth) below |
@@ -63,6 +63,41 @@ Copy to **`/usr/local/bin/`** (system) or **`~/.local/bin/`** (user), set **`GOP
> **earth gotcha:** `goprecords-upload-earth.sh` is a *copy of the generic* `goprecords-upload-client.sh`, so it aborts with `set GOPRECORDS_HOST` unless the var is provided. The service therefore **must** carry `Environment=GOPRECORDS_HOST=earth`. (A missing env var silently broke earth uploads for ~a month — symptom: stale timestamp on the report, service `status=1/FAILURE` with `set GOPRECORDS_HOST` in `journalctl --user -u goprecords-upload-earth`.)
+## Rocky Pi uptimed clock synchronization
+
+**pi2** and **pi3** have no hardware RTC. At boot their clocks initially use a stale timestamp until chronyd synchronizes with NTP. The packaged `uptimed.service` only declares `After=time-sync.target`; that target does not guarantee chronyd has obtained valid time. If uptimed starts too early, it records the stale boot date and goprecords may omit the host's `*` active marker because activity is calculated from the newest record's boot time plus uptime, not from upload time.
+
+Both Pis have this override at **`/etc/systemd/system/uptimed.service.d/time-sync.conf`**:
+
+```ini
+[Unit]
+Wants=network-online.target chronyd.service
+After=network-online.target chronyd.service
+
+[Service]
+ExecStartPre=/usr/bin/chronyc waitsync 60 0.5
+```
+
+Apply or verify it with:
+
+```sh
+sudo systemctl daemon-reload
+sudo systemd-analyze verify uptimed.service
+sudo systemctl restart uptimed
+systemctl show uptimed -p ExecStartPre -p ExecMainStartTimestamp
+```
+
+`chronyc waitsync 60 0.5` allows up to 60 attempts and starts uptimed once the remaining clock correction is at most 0.5 seconds. It works as the service's unprivileged `daemon` user.
+
+If a Pi already has a stale current record, restart uptimed after NTP is synchronized, then run the normal upload immediately:
+
+```sh
+sudo systemctl restart uptimed
+sudo systemctl start goprecords-upload.service
+```
+
+Check the source and uploaded records with `uprecords -a`, `/var/spool/uptimed/records`, and the goprecords `LastUpdated` report. This repaired pi3 on **2026-07-16**: its uploader had been healthy, but its only stored boot timestamp was from **2025-12-02**; restarting uptimed added the correct **2026-06-25** boot timestamp and restored the `*` marker. A subsequent pi3 reboot verified the override: chronyd stepped the stale clock at **13:00:57 UTC**, `chronyc waitsync` succeeded, and uptimed started afterward at **13:01:03 UTC** with the correct current boot date.
+
## Mac / mega-m3-pro via earth
The Mac (Apple Silicon, **`Darwin`**) is **not** a direct upload client. Instead:
diff --git a/prompts/skills/f3s/references/pihole-pi.md b/prompts/skills/f3s/references/pihole-pi.md
index b141826..3039926 100644
--- a/prompts/skills/f3s/references/pihole-pi.md
+++ b/prompts/skills/f3s/references/pihole-pi.md
@@ -36,6 +36,10 @@ dig @pi3.lan.buetow.org f3s.lan.buetow.org +short # expect 192.168.1.138
Admin UI: **`http://pi2.lan.buetow.org/admin/`** (and pi3).
+## Timekeeping on the RTC-less Pis
+
+pi2 and pi3 have no hardware RTC, so their clocks are stale briefly during boot until chronyd synchronizes. `uptimed` must not start in that window: both hosts use a systemd override that waits for `chronyc waitsync`, preventing invalid boot timestamps and missing active markers in goprecords. The canonical override, recovery procedure, and verification commands are in [goprecords-uptimed.md](goprecords-uptimed.md#rocky-pi-uptimed-clock-synchronization).
+
## Public DNS note
**`frontends/var/nsd/zones/master/buetow.org.zone.tpl`** already has **`*.f3s.lan IN A 192.168.1.138`** for authoritative **`buetow.org`**; Pi-hole on the LAN keeps the same mapping for clients that use pi2/pi3 as resolver.