diff --git a/.gitignore b/.gitignore index f26c0ed..1d4d860 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,9 @@ deploy/telegram.env deploy/zenmoney.token # IMAP password, read by mavmaild (never in argv, never committed) deploy/imap.password +# Compose interpolation secrets — MAVEN_AMBIENT_TOKEN today. docker compose +# reads this file itself; it is not an env_file on any service. +/.env # Temp files /tmp/ diff --git a/deploy/mavend.json b/deploy/mavend.json index 2908b4e..501e2dc 100644 --- a/deploy/mavend.json +++ b/deploy/mavend.json @@ -76,6 +76,56 @@ "snippet_runes": 1500 }, + "//morning_routines": [ + "The daily checklist (Vikunja #280). Each item is done when its fact_key", + "gets a non-voided fact inside the window, so 'выпил воды' closes water and", + "nothing has to be ticked by hand. nudge_at fires once, at the end of the", + "window, and only for what is still open. Weekdays empty = every day." + ], + "morning_routines": [ + { + "name": "утро", + "window_start": "08:00", + "window_end": "11:00", + "nudge_at": "10:30", + "severity": 1, + "items": [ + { "key": "medicine", "fact_key": "medicine", "label": "лекарство" }, + { "key": "water", "fact_key": "water", "label": "вода" }, + { "key": "pets", "fact_key": "pets", "label": "покормить кота" } + ] + } + ], + + "//feeds": [ + "RSS reading (Vikunja #258). Every item lands as a note with source", + "rss:, which is also what puts entries in the intake journal that", + "/events reads. Only the feed URL leaves the box.", + "This is a starting pair, not a curated set — trim or extend it." + ], + "feeds": { + "poll_interval": "30m", + "max_items": 5, + "max_age": "24h", + "sources": [ + { "name": "lwn", "url": "https://lwn.net/headlines/newrss", "category": "технологии" }, + { "name": "archlinux", "url": "https://archlinux.org/feeds/news/", "category": "технологии" } + ] + }, + + "//crawl": [ + "Reading a web page (Vikunja #259). on_demand answers 'посмотри '.", + "No allow_hosts, so any public host he names is readable; private", + "addresses are refused unconditionally by internal/webfetch and do not", + "need listing. Setting allow_hosts here would also narrow on-demand,", + "which is the point of leaving it empty." + ], + "crawl": { + "on_demand": true, + "timeout": "10s", + "max_runes": 4000 + }, + "digest": { "enabled": true, "window": "30m", @@ -119,7 +169,7 @@ "timeout": "400ms", "rate": 100, "max_hosts": 256, - "enabled": false + "enabled": true }, "nexus": { "url": "http://nexus:9740" }, diff --git a/docker-compose.yml b/docker-compose.yml index be5a6e9..ab84b8f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -79,7 +79,16 @@ services: <<: *image # voice.bind is 0.0.0.0:9100 in deploy/mavend.json so mavweb can reach it # cross-container. Verified 2026-07-06. + # -ambient-token turns on POST /api/ambient (Vikunja #126): the phone posts + # notification text, mavweb keeps only a meeting time. Empty ⇒ no route at + # all, which is what a missing MAVEN_AMBIENT_TOKEN gives. The value comes + # from the gitignored .env docker compose reads for interpolation, NOT from + # an env_file — flags are interpolated before any service env exists. + # Weakness worth naming: mavweb takes this as a flag, so it is visible in + # `ps` inside this container, unlike the zenmoney and IMAP secrets which are + # read from files. command: ["mavweb", "-addr", ":9201", "-voice", "mavend:9100", "-core", "/run/maven/mavend.sock", + "-ambient-token", "${MAVEN_AMBIENT_TOKEN:-}", "-nexus", "http://nexus:9740", "-praxis", "http://praxis:8989", "-hexis", "http://hexis:9741"] depends_on: [mavend] # loopback-only on purpose: /tools defines+executes arbitrary argv and diff --git a/docs/qa.md b/docs/qa.md index 5687782..5e08d5b 100644 --- a/docs/qa.md +++ b/docs/qa.md @@ -46,10 +46,15 @@ Sessions 1, 2 and 3 all ran. Read these five before picking anything up. with a general article about network hardware. A question about his LAN went to an upstream engine. The crawler fails the same way. -Twenty defects were filed on 02-08-2026: 462 through 481. Six tasks this plan +Twenty-one defects were filed on 02-08-2026: 462 through 482. Six tasks this plan had written off as blocked turned out to be ready to check. All six ran. Every one of them is code-correct and stops at the deploy. +Three of the five config blockers in **472** were then cleared. The morning +routine, ambient ingest, feeds, the crawler and netscan are all live. Two remain, +and both are the owner's call: a token for each ecosystem sibling, and seed data +in Nexus and Praxis. + --- ## Before you start @@ -256,6 +261,27 @@ its presence rule passes on inspection. Three of its five items need traffic the box has not had. **283 is blocked**: nothing feeds the intake journal. **128 found the worst defect of the whole session, see below.** +Three of 472's five blockers were cleared the same day, in `deploy/mavend.json` +and `docker-compose.yml`. + +- A `morning_routines` block, one routine `утро` 08:00-11:00 with medicine, + water and pets. It is live: the dispatcher logged `dropped morning:утро (sev1, + presence=away)`, so the plan builds and the nudge is proposed. 280's + behaviours and 128 step 11 are checkable now. 473 still stands. +- `-ambient-token` on mavweb, value in a gitignored `/.env` that docker compose + reads for interpolation. `/api/ambient` answers 401 without the token and 201 + with it, storing `calendar_event_20260802_Standup`. 283 step 5 and 128 step 8 + are unblocked. The token is a flag, so it shows in `ps` inside that container. + The zenmoney and IMAP secrets are read from files instead. Ingest also + reads the notification's wall clock as UTC and stores a 14:30 meeting at 18:30 + (**482**). +- `feeds` (two sources), `crawl.on_demand` and `netscan.enabled`. The intake + journal now fills: `/events` holds `scan:lan` and `ambient:notif` rows. + +Two are not mine to clear. No sibling has a `token` in `deploy/mavend.json`, so +273 steps 6 and 8 need a credential decision. Nexus has no entities and Praxis no +attention items, so 272 step 3 needs seed data whose content is the owner's call. + For **285**, two facts bear on the choice. Synapse is already running on this box and healthy, so a Matrix reach has a live target and needs no new service. And mavweb is already a PWA with a service worker, which 285 itself calls the highest @@ -451,6 +477,14 @@ need the block enabled. Step 10 is Bluetooth and stays skipped. **259, crawler.** Steps 1 and 15 pass. Step 2 fails. Steps 3 to 14 need a `crawl` block that nobody has written. +Both were configured later the same day, and both work. `netscan.enabled: true` +answers `какие устройства в сети?` with `нашла 3 устройства, из них 2 с вебом, 2 с +ssh. список записала.` and the scan lands in the intake journal as `scan:lan`. +`crawl.on_demand: true` answers `посмотри https://lwn.net — что там пишут?` from +the real page. So **479** is one defect, not the routing defect it was filed as. +An unconfigured capability declines its own turn instead of naming the gap. +Nothing is wrong with the routing. + 257 step 1 and 259 step 2 fail the same way and share a task (**479**). An unconfigured capability does not name the gap, so the question escapes to web search. `какие устройства в сети?` was answered with a general article about