Compare commits

..

2 Commits

Author SHA1 Message Date
Julien Calixte
d5f22c697c docs(v0.1-tech): switch Wi-Fi to on-demand model, off by default
Always-on station mode burns ~410 mAh/day on the radio alone; on-demand
drops that to ~25 mAh/day at 10 Publishes/day. Radio comes up on Ctrl-G
with a 10 s association timeout, holds for a ~90 s grace window after
each Publish, then tears down. SNTP cached up to 24 h to avoid
re-querying every Publish.

Also removes stale SoftAP provisioning bullets that contradicted the
"v0.1 has no provisioning module" stance later in the same doc.
2026-05-17 12:38:47 +02:00
Julien Calixte
cbdd6aa197 docs: lock device to one linear branch via Publish-is-sync principle
The user's mental model of Publish is a Google Doc backed by git, not a
curated commit log. Branches fall out of scope under that framing; the
device tracks one stream of work on whichever branch the remote was
cloned on, and never switches. Drops :Gbranch from v0.7 to match.
2026-05-17 12:38:36 +02:00
3 changed files with 33 additions and 11 deletions

View File

@@ -86,6 +86,12 @@ into user-facing language).
reconcile remote state in the background. If a previous **Publish** ended
mid-flight and left a local commit unpushed, the next user-initiated
**Publish** picks it up; until then, the device is silent about it.
- **Publish is sync, not history.** The user's mental model is a Google Doc
that happens to be backed by git: the point is "I want to read this on my
phone later," not "I want a curated commit log." Commits are a transport
detail the device authors itself. Branches are out of scope for the same
reason — the device tracks one linear stream of work on whichever branch
the remote was cloned on, and never switches.
- **No state the user didn't ask for.** No banners about pending work, no
prompts about divergence, no "did you mean to publish" warnings. The status
line reflects the _current_ action's outcome, nothing else.

View File

@@ -71,7 +71,6 @@ Out of scope: Vim, palette, multiple files, branches, conflict handling.
- [ ] `/` forward search, `n N`
- [ ] `:Gpull` (fetch + fast-forward only; refuse on conflict and surface it)
- [ ] `:Gbranch` to switch branches; refuse with dirty tree
## v0.8 — Power: battery + sleep — [ ]

View File

@@ -45,7 +45,7 @@ blocked by I/O.
| Task | Core | Stack | Responsibility |
| ------------- | ---- | ----- | -------------------------------------------------------- |
| `usb_task` | 0 | 8 KB | TinyUSB host loop, decode HID reports, post `KeyEvent`s |
| `wifi_task` | 0 | 8 KB | Station mode only (no provisioning AP); expose status |
| `wifi_task` | 0 | 8 KB | On-demand station: off by default, brought up by `Ctrl-G` |
| `ui_task` | 1 | 16 KB | Consume `KeyEvent`s, mutate editor state, enqueue render |
| `render_task` | 1 | 12 KB | Drain render queue, do partial/full refresh on EPD |
| `git_task` | 1 | 32 KB | Triggered by `Ctrl-G`; runs gitoxide commit + push |
@@ -67,7 +67,7 @@ read snapshot (render diff).
└─ present → continue
5. Init SPI bus (shared: EPD + SD on different CS)
6. Init EPD, full refresh: splash + boot log
7. Start tasks: usb, wifi (station), ui, render
7. Start tasks: usb, wifi (spawned in `Off` state — no radio bring-up), ui, render
8. ui_task opens /sd/repo/notes.md, places cursor, enqueues full render
9. STEADY STATE
```
@@ -156,15 +156,32 @@ Storage split rationale:
- The file is read fully into the rope at boot. v0.1 caps file size at
256 KB; larger files refuse to open with a clear message.
### `wifi` — provisioning + station
### `wifi` — on-demand station
- Provisioning: SoftAP `typewriter-setup`, captive-portal DNS, tiny HTTP
server (`esp-idf-svc::http`). Form submits config; on success, restart in
station mode.
- Station: reconnect with exponential backoff (1, 2, 5, 10, 30, 60 s, hold
at 60). Status exposed via a `WifiState` atomic enum.
- Time sync via SNTP — needed for commit timestamps. Failure is logged but
non-fatal; commits use device uptime if SNTP fails.
- **Off by default.** The radio is powered down (`esp_wifi_stop`) except
during a Publish and a short grace window after. This is the load-bearing
battery decision: always-on station mode burns ~410 mAh/day just for the
radio; on-demand is closer to ~25 mAh/day at 10 Publishes/day. See
[qfd.md H13](qfd.md#6-critical-performance-budget).
- **Bring-up on `Ctrl-G`.** `wifi_task` transitions `Off → Associating →
Connected`. Association timeout: 10 s. If association fails, the local
commit is preserved and the status line shows `⌁ ✗`; no background retry.
- **Grace window** of ~90 s after a Publish completes. A `Ctrl-G` inside
the window reuses the connection (no second association cost). If no
Publish fires before the window expires, the radio tears down.
- **No reconnect-backoff state machine.** There is nothing to reconnect to
when the user isn't trying to Publish. Single-shot try-on-demand replaces
the exponential-backoff approach.
- **SNTP** runs on the first successful bring-up of a power session. The
result is cached for up to 24 h; subsequent Publishes use the cached time
for the commit message. Falls back to device uptime if SNTP has never
succeeded — logged but non-fatal.
- **Status exposed via a `WifiState` atomic enum** (`Off`, `Associating`,
`Connected`, `Failed`).
On-device provisioning (SSID, PAT rotation, etc.) is deliberately deferred
to v0.9. v0.1 reads all config from the binary at build time — see
"Provisioning — build-time only" below.
### `git` — commit + push