openvibers/openvibe.watch CHANGELOG.md

CHANGELOG.md

main 7.7 KB · 107 lines · markdown

1# Changelog
2
3## 2026-11-09 — a routine is a watch with a cron (Actor's triggers)
4
5- **A schedule watch**: `POST /api/v1/watches/:id/schedule` saves a five-field cron and timezone (migration
6 `0021_actor_schedule`). The scheduler fires it like a cadence; `check.run` records the occurrence as a
7 `condition_met` run with carrier `schedule` and queues the watch's actions without fetching anything. The floor is 15
8 minutes, as it is for a cadence. The source stays a valid `watch.watch@1` kind (the subscription is created paused, a
9 webhook source is refused deliveries, and the routine never polls a page), so the released watch schema is unchanged.
10- **A watch that fails five checks in a row pauses itself** and says so (one `agent.step` ended step); resuming clears
11 the streak and arms it again. A routine's action then reaches Actor with `watch_id` and the Actor `trigger_id` from
12 the watch's `actor_trigger` label, so the run links back to its card.
13
14What shipped on OpenVibe.Watch, newest first. The plan is T18 ("Watch complete"); each entry names
15the step it landed.
16
17## 2026-11-06 — the chat apps' checks come from the SDK (agent plan A4)
18
19- Slack's v0 request signing, Discord's Ed25519 interaction signature and Telegram's secret token
20 are checked by `openvibe-sdk/chat-apps` (`verifySlack`, `verifyDiscord`, `verifyTelegram`), the
21 same code the chat bots use, instead of Watch's own copies (`server/webhook-sources.js`). The
22 behaviour is unchanged: the same five-minute window, the same exact raw bytes, the same
23 constant-time comparison, and a provider Watch does not know still checks nothing.
24- Pins openvibe-sdk v0.92.0 (was v0.82.0).
25
26## 2026-11-03 — email in (agent plan A3)
27
28- A webhook watch can have an email address of its own (`in-…@openvibe.watch`): mail sent there runs its check on the
29 sender, subject and text. Cloudflare Email Routing hands each message to the mail Worker (`edge/mail-worker.mjs`),
30 which posts it to `POST /hooks/email`, signed; an unknown address or a paused watch bounces the mail
31 (`server/webhook-sources.js`, `server/mail-parse.js`, migration `0016_webhook_email_address`).
32
33## 2026-11-01 — the condition in words, a quiet test before arming, and the evidence in every alert
34
35- The watch list and each watch page say the watch's structured condition in one sentence — what it reads, where,
36 and what makes it fire — instead of the condition operator alone (`server/render/watch.js`, `server/http/pages.js`).
37- A polling watch made on the site is saved paused and read once by a quiet test check before it arms. The watch page
38 shows the value that check found (or the state it recorded and why, when it found none), nothing is notified and no
39 action is queued, and the person arms it when ready. The first arm is stored in `watches.armed_at`
40 (migration `0014_armed_at.sql`, `server/check.js`, `server/http/pages.js`).
41- Every alert now carries its evidence: a notification's message and `rich_content`, a webhook body, an Actor task's
42 context and a run-job's firing argument state the value before and after, the source address and the time the value
43 was fetched. A part the watch did not store is left out (`server/actions.js`). The watch page's alert history shows
44 the same evidence (`server/http/pages.js`).
45- Tests: `test/site.test.js` (the quiet test, the failed test, arming, the condition in words, the arm badge),
46 `test/actions.test.js` (the notification and webhook evidence, the omitted line, the page history).
47
48## 2026-10-31 — a person's Network session token on the API
49
50- The watch API accepts a signed-in person's Network session token (`aud: openvibe.network`) as a Bearer, the same
51 token the site's SSO verifies, as well as a person/agent token minted for `openvibe.watch`. A first-party service
52 such as Shoes can therefore create a watch with the person's own token instead of a service token. The watch is
53 owned by the token's canonical `usr_…`/`agt_…` `subject_id` (a Network session token's `sub` is the numeric
54 account id), so project delegation and the person-only actions keep working. `server/auth.js`, `test/api.test.js`.
55
56## 2026-10-13 — check-operation usage readings (plan T5 step 14, Watch slice)
57
58- A completed check queues one `platform.usage-sample@1` reading (metric `check-operation`, quantity 1, unit `check`,
59 operation and provider the carrier, subject the owner, project only when the watch names one, cost the run's
60 `cost_usd`) in the transaction that records its run, keyed `watch:check:<run id>`; a failed check is not billed.
61- `server/billing.js` relays them to OpenVibe.Billing (`POST /api/v1/usage`, `billing.usage.record`) with the
62 `openvibe-sdk/usage` reporter; 400/422 rejects a reading, 429/5xx keeps it pending. `/api/ready` reports its counts.
63- Off by default (`WATCH_BILLING_INTERVAL_MS=0`). Migration `0008_billing_readings.sql`, `test/billing.test.js`.
64
65## 2026-10-08 — account export and deletion (ADR-033)
66
67- `POST /internal/events` (loopback, `WATCH_EVENTS_SECRET`) answers network.account.export_requested and
68 network.account.deleted through `server/account-data.js` over `openvibe-sdk/account-data` (SDK v0.37.0, was v0.36.0).
69- **Export:** the person's watches.
70- **Deletion:** their watches with every check run, observation and endpoint state under them, and their sessions.
71- The two subscriptions are created at boot. Migration `0003_account_data.sql`, nginx `location /internal/ { return 404; }`,
72 `test/account-data.test.js`.
73
74## 2026-10-08 — the public site (T18 step 8)
75
76- **Sign in with OpenVibe** at `/auth/login`: OAuth 2 authorization code with PKCE (S256) as the
77 Network client `watch`, a session in Watch's own database (only the hash of the cookie token is
78 stored), and the signed-in person's `usr_…` subject as the owner.
79- **A site for watches**: the home page explains Watch and starts one of the four kinds; `/watches`
80 lists yours; `/watches/:id` states a watch in plain words with its observation history and every
81 check run; pause, resume, delete and check-now are plain forms. Every page works without
82 JavaScript.
83- **One create form, four starting points** (`/watches/new?template=page|price|feed|json`): a page
84 that changes, a price below a value, a new item in a feed, a JSON value — the server picks the
85 fields the kind needs.
86- **Honest by construction**: the kinds that arrive later (event, webhook, Run, Node) and an AI
87 reading are not offered, because Watch will not pretend to check what it cannot. Notifications go
88 through OpenVibe.Network exactly as before.
89- **Crawl artifacts** (robots.txt, sitemap.xml, llms.txt) and a public vhost that serves the site
90 while `/api/v1/*` stays loopback-only.
91
92## 2026-10-08 — the check engine and the pull carriers (T18 steps 2–3)
93
94- **The watch registry**: `watch.watch@1` in and out, validated with the released contracts; a
95 create needs a source, an extraction, a condition and an action; ownership is the authority and
96 another owner's watch is 404.
97- **The check engine**: conditional GET (ETag/Last-Modified, a 304 costs no body), HEAD-first when
98 only "did it change?" matters, an unchanged body recorded as `no_change`, and a recorded state for
99 every terminal path with backoff and `Retry-After`.
100- **Carriers**: `http`, `feed` (RSS 2.0 / RSS 1.0 / Atom 1.0) and `api` (JSON/XML, mapped), all
101 through the one SSRF-guarded fetcher with per-host spacing.
102- **Extraction and conditions**: text, html, a small CSS subset, json/jsonpath and regex; `changed`,
103 the numeric and string predicates, `for_sec` debounce, tolerance and percent.
104- **Observations and check runs**: immutable rows with value hashes, capped snapshots and retention.
105- **The API** (bearer tokens, one capability per route), the `watch.*` events through the
106 transactional outbox, and per-actor limits.
107