Files
clockwork-hero/docs/PROTOCOL.md
Mystica Venatus 55480b3fc6 feat(face): integrate Idle Task Protocol v1.0 end-to-end
Watchface now syncs with the Nine Hazes idle task system via its own
pkjs client — the three-artifact architecture is operational.

Wire side:
- pkjs fetches GET /v1/queue on launch, applies clock offset, converts
  epoch-ms to seconds for AppMessage, resolves task name from the
  cached dictionary (refetch on version drift)
- GameSnapshot persisted at key 0x30 (protocol-specified); task name
  at 0x32 (face-local nicety)
- AppMessage inbox widened to 256 bytes to carry the full snapshot
  dictionary in a single logical message

Display side:
- Task strip renders two lines: countdown-to-completion + used/36 +
  task count, then task name with "(+)" pending-rewards cue
- Status states render distinctly: FROZEN / ABORTED(code) / LOCKED /
  No hero yet (EMPTY)
- serverDown sentinel key: oxblood "!" icon on failed check; absence
  on successful sync clears it; volatile — never persisted
- Countdown math is server-clock corrected (clock_off), computed
  locally from bound_sec — zero radio to stay fresh

Also:
- ES5-normalized pkjs for SDK webpack 1.15/acorn parser
- Replaced face_packet.{h,c} with snapshot.{h,c} (PACKET_KEY 101
  retired; old blob orphaned harmlessly)
- Mock Task API server seeded with 3-task queue (in-memory)

Verified: seeded queue renders "0:xx 16/36 seg 3 tasks / Gather (+)";
server kill → cached strip + offline icon, no error surface.
2026-09-13 10:18:34 -04:00

90 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Nine Hazes — Watch Client for OSRIC MUD Idle System
## Consolidated record v3.0 (post-pivot, 2026-09-12)
### 1. Concept
Pebble Time 2 (emery) watchface + companion watchapp acting as remote monitor
and manager for the Nine Hazes OSRIC MUD idle task system. NOT a standalone
game — all game logic lives on the MUD server. The watch displays server
snapshots and submits intents (add/cancel/claim); the server validates and
executes. Watch behaves like a normal watchface except during active sync.
### 2. Critical architecture decision — "face gets its own sync"
Pebble persist storage is per-app sandboxed with NO app↔app communication
(verified against platform docs). Therefore the watchface and watchapp each
own an independent pkjs sync to the same Task API. No watch-side data sharing
exists or is attempted. Shared truth = server.
### 3. Protocol
Wire contract: "Nine Hazes — Idle Task Protocol v1.0" (separate document,
authored server-side; authoritative). Summary:
- HTTPS + Bearer token (scoped queue:read queue:write claim; token on phone
localStorage only, NEVER on watch)
- GET /v1/dictionary (versioned, 304-style caching via ?v=)
- GET /v1/queue — full sync in one call (tasks[], used/budget, pend, bound,
status, tok.exp)
- POST /v1/queue/tasks (reqId idempotency), DELETE /v1/queue/tasks/:tid,
POST /v1/claim, POST /v1/token/refresh
- Device protocol: GameSnapshot packed struct (~28 bytes) at persist key 0x30;
dictionary blob at 0x31 (watchapp use)
- Clock correction: all countdowns from bound + clock_off, never raw watch clock
- Failure ladder: unreachable/malformed → silent, render cached snapshot
### 4. Artifacts & ownership
| Artifact | Owner | Status |
|---|---|---|
| Watchface (C, canvas renderer, widget table) | watch team | RENDERING BASELINE COMPLETE: custom-canvas data-driven renderer, 10 widget types + 2 spare slots, per-widget layout persist (key 100), parchment/ink palette, task strip rendering, server-down icon, dev.sh tooling. Committed to Gitea. |
| Watchapp (queue manager UI) | watch team | deferred (build order item) |
| pkjs ×2 (face sync, watchapp sync) | watch team | face pkjs fetches /v1/queue → AppMessage snapshot |
| Bridge/state server | OBSOLETE — deleted. Superseded by MUD gateway + placeholder mock (below) |
| Placeholder mock server (idle protocol §10) | watch team | zero-dependency node:http implementation (NOT Express — locked project law: TypeScript, node stdlib only) |
### 5. Widget set (unchanged)
Time, date, watch battery (+days estimator, key 102), phone battery, steps,
distance, weather composite (NWS default / Open-Meteo fallback — geographic
auto-switch), advisory omens, sleep, Current Task Strip (2-line: line 1 =
countdown to task completion + used/36 + task count, line 2 = current task
name (+n) pending indicator; offline "!" icon on failed check). All
toggleable/movable/font+color stylable. Spare slots reserved (incl. game
preview / companion preview, deferred).
### 6. Design laws (north stars)
1. Casual glance — no game-triggered interrupts, ever.
2. Game logic dormant until invited; watch computes only countdown strings.
3. Fully free face — no protected widgets; "restore default" escape hatch.
4. Face shows minimal: countdown + queue line only.
5. Battery-first: zero network in ambient use; one sync per interaction.
6. Fail-dead-silent: server down → cached data or hidden strip; no errors.
7. Zero-dependency TypeScript server code; no workers/background radio ever;
wakeups = semantic events only, rolling single wakeup (Muninn pattern).
### 7. Platform/environment
emery only ("targetPlatforms": ["emery"]) · Core Devices PebbleOS SDK ·
system fonts first (carved from Apache release), OFL TTFs bundled later ·
Apache-2.0 · Gitea master (auth-gated), GitHub public mirror at v0.1.0 ·
Liberapay/Ko-fi FUNDING.yml.
### 8. Reference projects (ideas only, clean-room; unlicensed repos = read-for-protocol
never copy code; Remix-on-CloudPebble ≠ redistribution grant)
IdleFantasy (queue model), Doors of Doom (AppMessage), Pixel8 (chunked
transfer), Muninn (wakeup/battery sampling patterns), Tamagotchi-API/TamaTime
(companion-preview idea, DEFERRED — feature not focus).
### 9. Build order (current)
1. ✔ Watchface rendering baseline (committed)
2. ✔ pkjs fetch + AppMessage + cached-packet strip + offline icon (v1 protocol)
3. → NOW: idle-protocol adaptation — snapshot struct, mock server, clock-offset
countdown (this revision)
4. Widget wiring: health (steps/distance/sleep), weather (NWS/Open-Meteo)
5. Watchapp: queue UI (add via presets/segment picker, cancel, claim),
wakeup at segment boundary, launch_args deep links, App Glance/timeline pins
6. Settings phase 2: hosted config page (drag-drop layout, presets, server URL/
token entry)
7. Polish: PDC sprites/icons (pickaxe, fist, coin, moon), theme, vibration
### 10. Open items to relay to server team
- bound/t/sync timestamps in epoch-ms exceed AppMessage uint32 → watchface
uses epoch-SECONDS for wire transfer (recommend protocol clarify units)
- Face receives resolved task NAME from pkjs (v1); dictionary blob 0x31 is
watchapp-scoped, chunked transfer deferred
- Player identity: X-Pebble-Id informational; real auth = MUD token