From 9114d9be2fa446af48c451785b797513d14d53e3 Mon Sep 17 00:00:00 2001 From: vitaliytv Date: Wed, 22 Jul 2026 06:57:40 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=93=9D=20docs(mt):=20=D0=B3=D0=BB?= =?UTF-8?q?=D0=B0=D0=B2=D0=B0=20recurrence=20=E2=80=94=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D1=80=D1=8E=D0=B2=D0=B0=D0=BD=D1=96=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=B4=D0=B0=D1=87=D1=96=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7?= =?UTF-8?q?=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=20+=20=D1=96=D0=BD?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BD=D1=81=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ОАГ ациклічний і resolved термінальний — повторюваність у графі не виражалась. Новий механізм: мутабельний шаблон у .mt/templates// (не вузол), планувальник у wake-логіці матеріалізує на кожне спрацювання звичайний кореневий вузол mt/-YYYYMMDD-hhmm/ одним fenced commit (детермінований id → ідемпотентність, гонка хостів — штатним publish). Розклад: повний 5-польний cron (schedule, tz) або інтервальний every, відв'язаний від календаря; політики overlap/catchup/keep; CLI mt template list|run. Стан планувальника derived (template:/occurrence: у task.md інстансів). Відхилені альтернативи зафіксовано у главі. Перехресно: зміст (index), глосарій (overview), CLI/cleanup/довідник ключів (operations), журнал (log), change-файл, словник cspell. Co-Authored-By: Claude Fable 5 --- .cspell.json | 11 ++++ npm/.changes/260722-0643.md | 5 ++ npm/docs/architecture/index.md | 1 + npm/docs/architecture/operations.md | 7 ++- npm/docs/architecture/overview.md | 2 + npm/docs/architecture/recurrence.md | 89 +++++++++++++++++++++++++++++ npm/docs/index.md | 1 + npm/docs/log.md | 4 ++ 8 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 npm/.changes/260722-0643.md create mode 100644 npm/docs/architecture/recurrence.md diff --git a/.cspell.json b/.cspell.json index 367ef8c..eca7ce4 100644 --- a/.cspell.json +++ b/.cspell.json @@ -229,6 +229,7 @@ "інвалідовуються", "інвалідування", "Інвалідувати", + "інвалідаціями", "інвалідує", "інвентаря", "інжект", @@ -237,6 +238,16 @@ "інжекту", "інкрементує", "інлайн", + "інстанс", + "Інстанс", + "інстанса", + "інстансам", + "інстансами", + "інстанси", + "Інстанси", + "інстансів", + "інстансом", + "інстансу", "інтейк", "ітеративно", "Ітеративно", diff --git a/npm/.changes/260722-0643.md b/npm/.changes/260722-0643.md new file mode 100644 index 0000000..df9ae05 --- /dev/null +++ b/npm/.changes/260722-0643.md @@ -0,0 +1,5 @@ +--- +bump: patch +section: Added +--- +docs: глава архітектури `recurrence.md` — повторювані задачі через шаблон (`.mt/templates/`) + інстанси-кореневі вузли; політики overlap/catchup/retention, CLI `mt template list|run`; перехресні оновлення index/overview/operations/log diff --git a/npm/docs/architecture/index.md b/npm/docs/architecture/index.md index 08959f8..59f2d57 100644 --- a/npm/docs/architecture/index.md +++ b/npm/docs/architecture/index.md @@ -13,6 +13,7 @@ * [Мандати й людино-центрична ескалація](mandates.md) - карта мандатів, профілі людей і моделей, decision-request, маршрутизація за важелем, прецедентний рушій * [Багатомовність (i18n)](i18n.md) - base-канон і derived-переклади у `refs/mt/i18n`, worktree-матеріалізація, contract-aware перекладач, authored-захист * [Мета-цикл (retro)](retro.md) - ретроспективний аналіз audit trail, приватні opt-in пропозиції виконавцю, застосування штатними правками +* [Повторювані задачі (recurrence)](recurrence.md) - мутабельний шаблон у `.mt/templates/`, матеріалізація інстансів планувальником wake, політики overlap/catchup/retention * [Експлуатація](operations.md) - CLI-контракт, конфігурація, монорепо, security model, відмовостійкість, bootstrap, Definition of Done ## Довідково diff --git a/npm/docs/architecture/operations.md b/npm/docs/architecture/operations.md index 9f9976e..3bca92c 100644 --- a/npm/docs/architecture/operations.md +++ b/npm/docs/architecture/operations.md @@ -30,11 +30,15 @@ mt sessions ← активні run-и акаунта, вк (хто де, хто тримає claim, моя роль) mt invite --role host|approver|viewer mt members + +# повторювані задачі (НОВЕ) +mt template list ← шаблони + наступне спрацювання + останній інстанс +mt template run ← позачергова матеріалізація (occurrence = now) ``` `mt watch`/`mt run --auto` зберігаються як однопострільні входи тієї самої логіки, що живе в agent-server (fallback-режим без сервера). Exit codes `mt scan`/`mt watch`: `0` — ок, `1` — є вузли, що потребують уваги. -`mt cleanup [--older-than N]` (дефолт 7 днів): orphan worktrees без active claim, мертві running-маркери, remote orphan run refs (старші `run_ref_ttl_days`), протухлі archive refs (старші `archive_ttl_days`). +`mt cleanup [--older-than N]` (дефолт 7 днів): orphan worktrees без active claim, мертві running-маркери, remote orphan run refs (старші `run_ref_ttl_days`), протухлі archive refs (старші `archive_ttl_days`), resolved-інстанси шаблонів понад `keep` ([recurrence.md](recurrence.md)). ## Конфігурація (`.mt.json`) @@ -76,6 +80,7 @@ Baseline-ключі 0.2.0 з конкретними дефолт-значенн | Паралелізм | `agent_concurrency` | [git.md](git.md) | | Виконавці/моделі | ENV: `MT_AGENT_CLI`, `MT_CLOUD_AGENT_CLIS`, `MT_AGENT_CLI_MODEL_MAP` | [runtime.md](runtime.md), [stack.md](stack.md) | | Поверхні/тули | `surface_profiles`, `mcp_servers` | [surfaces.md](surfaces.md) | +| Повторюваність | `templates_dir`; per-template `recurrence.md` (`schedule`/`every`, `tz`, `overlap`, `catchup`, `keep`) | [recurrence.md](recurrence.md) | | Безпека | `skill_profiles` (sandbox), `secrets` (у `a.md`), `require_signed_approvals`, `device_key_path` | тут, [access.md](access.md) | | Relay/хост | `relay_url`, `server_port_file` | тут, [runtime.md](runtime.md) | | i18n | `i18n.{base_lang, eager, publish_langs, include, exclude, model_tier, ttl_days}` | [i18n.md](i18n.md) | diff --git a/npm/docs/architecture/overview.md b/npm/docs/architecture/overview.md index f074f2a..b1d7479 100644 --- a/npm/docs/architecture/overview.md +++ b/npm/docs/architecture/overview.md @@ -73,6 +73,8 @@ timestamp: 2026-07-07 | **approver** | роль учасника, що підписує approvals з будь-якого пристрою **без git-доступу** | [access.md](access.md) | | **base-мова** | канонічна мова контенту в `main`; переклади — derived у `refs/mt/i18n/*` | [i18n.md](i18n.md) | | **authored-переклад** | версія мовою автора правки; захищена від перезапису зворотним перекладом | [i18n.md](i18n.md) | +| **шаблон** | мутабельний опис повторюваної задачі поза графом (`.mt/templates//`); не вузол | [recurrence.md](recurrence.md) | +| **інстанс** | звичайний кореневий вузол, матеріалізований із шаблона на спрацювання розкладу | [recurrence.md](recurrence.md) | | **мандат** | зона, у межах якої власник вирішує сам без ескалації (`.mt/mandates.yaml`) | [mandates.md](mandates.md) | | **decision-request** | упакована для власника розвилка: контекст, варіанти, рекомендація агента | [mandates.md](mandates.md) | | **leverage-фасети** | декларативні поля розвилки (незворотність, blast radius, дивергенція, ціна) з детермінованим мапінгом на режим ескалації | [mandates.md](mandates.md) | diff --git a/npm/docs/architecture/recurrence.md b/npm/docs/architecture/recurrence.md new file mode 100644 index 0000000..eac45e2 --- /dev/null +++ b/npm/docs/architecture/recurrence.md @@ -0,0 +1,89 @@ +--- +type: architecture +description: 'Повторювані задачі: мутабельний шаблон поза графом, матеріалізація інстансів планувальником wake, політики overlap/catchup/retention' +tags: [recurrence, templates, scheduler] +timestamp: 2026-07-22 +--- + +# Повторювані задачі (recurrence) + +> Частина цільової архітектури **0.3.0-draft** — [зміст](index.md) · [огляд](overview.md) + +## Концепція + +Повторюваність **не живе всередині графа**: ОАГ ациклічний, `resolved` — термінальний стан, артефакти immutable — вузол не може «виконатись і чекати наступного разу». Механізм — **шаблон + інстанси**: + +- **Шаблон** — мутабельний опис задачі поза `mt/` (у `.mt/templates/`); **не вузол**, scan його не бачить, станів не має. Правка шаблона діє з наступної матеріалізації й не торкається минулих інстансів. +- **Інстанс** — звичайний кореневий вузол `mt/-/`, матеріалізований планувальником на кожне спрацювання розкладу. Після матеріалізації він нічим не відрізняється від вузла, створеного `mt init`: ті самі стани, retry ladder, аудит, i18n, membership. Жодних нових derived-станів механізм не додає. + +Кожне повторення отримує **власну ідентичність і повний version chain** (run-и, fact-и, аудити) — «звіт за цей тиждень» — окремий immutable артефакт, а не перезаписаний результат одного вузла. + +## Файловий контракт шаблона + +``` +.mt/templates// + task.md ← схема task.md БЕЗ created_at/parent (заповнюються при матеріалізації) + a.md | h.md ← хто виконує інстанси (контракт graph.md, ніколи обидва) + recurrence.md ← розклад і політики (нижче) + deps/ ← опціонально: постійні deps інстансів (абсолютні dep-id від mt/) +``` + +`` — за naming convention вузлів (`a-z`, `0-9`, `-`). Директорія в `.mt/` свідомо: усередині `mt/` шаблон світився б у scan як `orphan-node`. + +### `recurrence.md` + +```yaml +schema_version: 1 +created_at: ISO8601 +schedule: '*/15 9-18 * * 1-5' # повноцінний cron, 5 полів, хвилинна гранулярність +every: 90m # АБО інтервал: 30m | 4h | 3d — відлік від попереднього occurrence +tz: Europe/Kyiv # опціонально; default UTC; впливає лише на обчислення cron +enabled: true # false → пауза без видалення шаблона +overlap: skip # skip | chain | parallel (нижче) +catchup: collapse # collapse | all — надолуження після простою +keep: 20 # retention resolved-інстансів; 0 → без GC +``` + +Рівно **одне** з `schedule`/`every`; обидва або жодного → fail closed. Два типи розкладу свідомо: + +- **`schedule`** — календарний: повний cron-вираз будь-якої частоти («щопонеділка о 3:00», «кожні 15 хв у робочі години»); обчислюється у `tz`. +- **`every`** — інтервальний, **відв'язаний від календаря**: наступне спрацювання = попередній `occurrence` + інтервал (sliding, без вирівнювання по добі). Cron принципово не виражає «кожні 90 хв» — для цього і є `every`. + +**Хвилина — свідома нижня межа гранулярності**: матеріалізація — це fenced-коміт у remote, а точність спрацювання обмежена wake-механізмом (таймер живого agent-server точний; cron-fallback — з точністю частоти rescan). Суб-хвилинні розклади — не кейс графа задач. + +## Матеріалізація інстанса + +Планувальник — частина wake-логіки orchestrator-а ([runtime.md](runtime.md#wake-push-замість-polling)): agent-server ставить таймер на найближче спрацювання серед шаблонів; cron/periodic rescan — fallback, що гарантує спрацювання без always-on процесу (з точністю до частоти rescan). + +На кожне спрацювання: + +1. **Id інстанса — детермінований від моменту спрацювання**, уніфіковано для будь-якої частоти: `-YYYYMMDD-hhmm` (occurrence у UTC, хвилинна точність — жодних спец-випадків «денного» формату). Той самий occurrence → той самий id → повторна спроба ідемпотентна. +2. Матеріалізуються `task.md` (+ `created_at` = момент спрацювання і два нові опційні поля фронтматеру — `template: `, `occurrence: ISO8601`), прапор `a.md`/`h.md` і `deps/` з шаблона — **одним fenced atomic commit** (актор — wrapper), як `mt spawn --approve`. +3. Гонка хостів вирішується штатно: два agent-server прокинулись одночасно → обидва зібрали ідентичний вузол → перший fenced publish виграє, другий після rescan бачить наявний id і пропускає крок. + +Інстанси — **кореневі вузли**, тож легітимні за інваріантом graph.md без змін (approved-план батька для них не потрібен). Групування — префіксом імені; підвішування інстансів під живий composite-вузол неможливе за побудовою: його `## Children` immutable після approve. + +**Стан планувальника — derived, як усе інше**: жодних лічильників чи "last-run"-файлів. Останнє спрацювання відновлюється скануванням вузлів із `template: ` (max `occurrence`); годинник + `schedule`/`every` дають наступне. + +## Політики + +- **`overlap`** — що робити, коли настало спрацювання, а попередній інстанс ще не `resolved`: + - `skip` (default) — нічого не матеріалізувати; пропущені occurrence підпадають під `catchup`; + - `chain` — матеріалізувати з автоматичним dep на попередній інстанс: виконання серіалізується, а fact попереднього стає входом наступного (потік даних між повтореннями — задарма через штатний механізм `deps/`; ланцюжок лишається ОАГ); + - `parallel` — матеріалізувати незалежно. +- **`catchup`** — надолуження після простою (вимкнена машина, довгий `skip`): `collapse` (default) — один інстанс за найсвіжішим пропущеним occurrence, без бекфілу; `all` — по інстансу на кожне пропущене спрацювання. +- **Retention** — розширення `mt cleanup` ([operations.md](operations.md)): resolved-інстанси понад `keep` найсвіжіших прибираються штатним kill-архівом (`/.history/`). `failed`/`unresolvable` інстанси GC **не чіпає** — вони чекають людину, як будь-який вузол. + +## CLI + +``` +mt template list ← шаблони + наступне спрацювання + останній інстанс +mt template run ← позачергова матеріалізація (occurrence = now) +``` + +Конфіг: `.mt.json` → `templates_dir` (default `.mt/templates`). Решта політик — per-template у `recurrence.md`; глобальних ключів механізм не додає. + +## Відхилені альтернативи + +- **Freshness/TTL прийнятого fact** (`schedule:` у `task.md` вузла: fact, старший за період → знову `waiting`) — мінімальна дельта до derived-станів і готова каскадна інвалідація нащадків, але повторення втрачають окрему ідентичність: NNN-ланцюжок одного вузла росте необмежено, `failed_streak`/`budget_total_sec` вимагають per-occurrence скидання, а «звіт за минулий тиждень» існує лише в git-історії. Може повернутись окремим механізмом для refresh-класу задач («тримай дані свіжими»), якщо dogfood покаже потребу. +- **Періодичний `mt invalidate` зовнішнім планувальником** — працює без змін контракту, але семантично хибний: invalidate означає «результат неправильний», а не «настав наступний цикл», і засмічує `history/`-архів та audit trail хибними інвалідаціями. diff --git a/npm/docs/index.md b/npm/docs/index.md index b64aedd..509b9e7 100644 --- a/npm/docs/index.md +++ b/npm/docs/index.md @@ -26,6 +26,7 @@ docgen: * [Мандати й людино-центрична ескалація](architecture/mandates.md) - карта мандатів, профілі людей і моделей, decision-request, маршрутизація за важелем, прецедентний рушій * [Багатомовність (i18n)](architecture/i18n.md) - base-канон і derived-переклади, worktree-матеріалізація, contract-aware перекладач * [Мета-цикл (retro)](architecture/retro.md) - аналіз audit trail, приватні opt-in пропозиції виконавцю +* [Повторювані задачі (recurrence)](architecture/recurrence.md) - шаблон + інстанси: розклад поза графом, кожне спрацювання — звичайний кореневий вузол * [Експлуатація](architecture/operations.md) - CLI, конфігурація, security model, відмовостійкість, наскрізні сценарії * [Референсний стек](architecture/stack.md) - технологічні рішення реалізації (Rust device-шар, Bun relay/`@7n/mt`) diff --git a/npm/docs/log.md b/npm/docs/log.md index 99f7d7d..7d8cb3b 100644 --- a/npm/docs/log.md +++ b/npm/docs/log.md @@ -1,5 +1,9 @@ # Журнал змін документації +## 2026-07-22 + +* **Creation**: [architecture/recurrence.md](architecture/recurrence.md) — глава повторюваних задач (закриває прогалину: ОАГ ациклічний, `resolved` термінальний — повторюваність у графі не виражалась). Механізм — **шаблон + інстанси**: мутабельний шаблон у `.mt/templates//` (task.md без `created_at`/`parent`, прапор `a.md`/`h.md`, `recurrence.md` із розкладом — повноцінний 5-польний cron `schedule` у `tz` АБО інтервальний `every` («кожні 90 хв»), відв'язаний від календаря; хвилинна гранулярність як свідома нижня межа — і політиками, опційні `deps/`) — не вузол, scan його не бачить; на спрацювання планувальник (частина wake-логіки orchestrator-а, cron-fallback гарантує без always-on) матеріалізує **звичайний кореневий вузол** `mt/-YYYYMMDD-hhmm/` (уніфікований id, occurrence у UTC) одним fenced atomic commit — детермінований id від occurrence робить створення ідемпотентним, гонка хостів вирішується штатним fenced publish. Стан планувальника derived (нові поля фронтматеру `template:`/`occurrence:` в task.md інстанса, жодних лічильників). Політики: `overlap: skip | chain | parallel` (chain = auto-dep на попередній інстанс — серіалізація + потік даних між повтореннями через штатний `deps/`), `catchup: collapse | all`, retention `keep` через розширення `mt cleanup` (kill-архів; `failed`/`unresolvable` GC не чіпає). Нові CLI `mt template list|run`, ключ `templates_dir`. Відхилені альтернативи зафіксовано у главі: freshness/TTL прийнятого fact (втрата окремої ідентичності повторень; може повернутись для refresh-класу) і періодичний `mt invalidate` (семантично хибний — засмічує audit trail). Оновлено: [architecture/index.md](architecture/index.md), [index.md](index.md), [architecture/overview.md](architecture/overview.md) (2 терміни глосарію), [architecture/operations.md](architecture/operations.md) (CLI-блок, `mt cleanup`, довідник ключів). + ## 2026-07-12 * **Update**: [architecture/stack.md](architecture/stack.md) — секцію пакетної межі звужено: тришаровий поділ (`contract`/`napi`/`mt` з rename-міграцією) **прибрано** — пакетні межі окупаються за незалежних споживачів/версіонування, яких немає (єдиний споживач — монорепа, публікація й так відкладена), а межа «рушій ↔ клієнт» тримається дешевше CI-перевірками за патерном `agent-core`. Лишається справжня цінність spec-а: **`@7n/mt-contract` + conformance-suite** (схеми, `states.md`, golden-fixtures, незалежна перевірка Rust і JS проти спільної точки істини) — два add-only PR без пересування тек. From cd182b2e78349512022a52ed70e222d04261d6b0 Mon Sep 17 00:00:00 2001 From: vitaliytv Date: Wed, 22 Jul 2026 07:01:18 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9D=20docs(mt):=20recurrence=20?= =?UTF-8?q?=E2=80=94=20=D1=81=D0=B5=D0=BC=D0=B0=D0=BD=D1=82=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BF=D0=B0=D1=83=D0=B7=D0=B8=20(enabled:=20false=20?= =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20catchup-=D0=B1=D0=BE=D1=80=D0=B3=D1=83)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Період паузи не породжує «пропущених» спрацювань: catchup надолужує простій системи, пауза — свідоме рішення людини. Після ввімкнення відлік з нуля (schedule — найближчий cron, every — від моменту ввімкнення, derived з git-історії recurrence.md — лічильників немає). Co-Authored-By: Claude Fable 5 --- npm/docs/architecture/recurrence.md | 1 + npm/docs/log.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/npm/docs/architecture/recurrence.md b/npm/docs/architecture/recurrence.md index eac45e2..4770866 100644 --- a/npm/docs/architecture/recurrence.md +++ b/npm/docs/architecture/recurrence.md @@ -72,6 +72,7 @@ keep: 20 # retention resolved-інстансів; 0 → б - `chain` — матеріалізувати з автоматичним dep на попередній інстанс: виконання серіалізується, а fact попереднього стає входом наступного (потік даних між повтореннями — задарма через штатний механізм `deps/`; ланцюжок лишається ОАГ); - `parallel` — матеріалізувати незалежно. - **`catchup`** — надолуження після простою (вимкнена машина, довгий `skip`): `collapse` (default) — один інстанс за найсвіжішим пропущеним occurrence, без бекфілу; `all` — по інстансу на кожне пропущене спрацювання. +- **Пауза (`enabled: false`)** — планувальник шаблон ігнорує; період паузи **не породжує «пропущених» спрацювань**: повернення `enabled: true` не запускає catchup за час паузи (catchup надолужує простій *системи*, пауза — свідоме рішення людини). Після ввімкнення відлік з нуля: для `schedule` — найближче майбутнє спрацювання cron, для `every` — момент ввімкнення + інтервал (момент ввімкнення — derived з git-історії `recurrence.md`: коміт, що виставив `enabled: true`; лічильників, як і скрізь, немає). Перемикання — звичайна правка мутабельного шаблона; поточний стан і наступне спрацювання видно у `mt template list`. - **Retention** — розширення `mt cleanup` ([operations.md](operations.md)): resolved-інстанси понад `keep` найсвіжіших прибираються штатним kill-архівом (`/.history/`). `failed`/`unresolvable` інстанси GC **не чіпає** — вони чекають людину, як будь-який вузол. ## CLI diff --git a/npm/docs/log.md b/npm/docs/log.md index 7d8cb3b..cb5ce02 100644 --- a/npm/docs/log.md +++ b/npm/docs/log.md @@ -2,7 +2,7 @@ ## 2026-07-22 -* **Creation**: [architecture/recurrence.md](architecture/recurrence.md) — глава повторюваних задач (закриває прогалину: ОАГ ациклічний, `resolved` термінальний — повторюваність у графі не виражалась). Механізм — **шаблон + інстанси**: мутабельний шаблон у `.mt/templates//` (task.md без `created_at`/`parent`, прапор `a.md`/`h.md`, `recurrence.md` із розкладом — повноцінний 5-польний cron `schedule` у `tz` АБО інтервальний `every` («кожні 90 хв»), відв'язаний від календаря; хвилинна гранулярність як свідома нижня межа — і політиками, опційні `deps/`) — не вузол, scan його не бачить; на спрацювання планувальник (частина wake-логіки orchestrator-а, cron-fallback гарантує без always-on) матеріалізує **звичайний кореневий вузол** `mt/-YYYYMMDD-hhmm/` (уніфікований id, occurrence у UTC) одним fenced atomic commit — детермінований id від occurrence робить створення ідемпотентним, гонка хостів вирішується штатним fenced publish. Стан планувальника derived (нові поля фронтматеру `template:`/`occurrence:` в task.md інстанса, жодних лічильників). Політики: `overlap: skip | chain | parallel` (chain = auto-dep на попередній інстанс — серіалізація + потік даних між повтореннями через штатний `deps/`), `catchup: collapse | all`, retention `keep` через розширення `mt cleanup` (kill-архів; `failed`/`unresolvable` GC не чіпає). Нові CLI `mt template list|run`, ключ `templates_dir`. Відхилені альтернативи зафіксовано у главі: freshness/TTL прийнятого fact (втрата окремої ідентичності повторень; може повернутись для refresh-класу) і періодичний `mt invalidate` (семантично хибний — засмічує audit trail). Оновлено: [architecture/index.md](architecture/index.md), [index.md](index.md), [architecture/overview.md](architecture/overview.md) (2 терміни глосарію), [architecture/operations.md](architecture/operations.md) (CLI-блок, `mt cleanup`, довідник ключів). +* **Creation**: [architecture/recurrence.md](architecture/recurrence.md) — глава повторюваних задач (закриває прогалину: ОАГ ациклічний, `resolved` термінальний — повторюваність у графі не виражалась). Механізм — **шаблон + інстанси**: мутабельний шаблон у `.mt/templates//` (task.md без `created_at`/`parent`, прапор `a.md`/`h.md`, `recurrence.md` із розкладом — повноцінний 5-польний cron `schedule` у `tz` АБО інтервальний `every` («кожні 90 хв»), відв'язаний від календаря; хвилинна гранулярність як свідома нижня межа — і політиками, опційні `deps/`) — не вузол, scan його не бачить; на спрацювання планувальник (частина wake-логіки orchestrator-а, cron-fallback гарантує без always-on) матеріалізує **звичайний кореневий вузол** `mt/-YYYYMMDD-hhmm/` (уніфікований id, occurrence у UTC) одним fenced atomic commit — детермінований id від occurrence робить створення ідемпотентним, гонка хостів вирішується штатним fenced publish. Стан планувальника derived (нові поля фронтматеру `template:`/`occurrence:` в task.md інстанса, жодних лічильників). Політики: `overlap: skip | chain | parallel` (chain = auto-dep на попередній інстанс — серіалізація + потік даних між повтореннями через штатний `deps/`), `catchup: collapse | all`, пауза `enabled: false` (період паузи не породжує catchup-боргу; момент ввімкнення — derived з git-історії `recurrence.md`), retention `keep` через розширення `mt cleanup` (kill-архів; `failed`/`unresolvable` GC не чіпає). Нові CLI `mt template list|run`, ключ `templates_dir`. Відхилені альтернативи зафіксовано у главі: freshness/TTL прийнятого fact (втрата окремої ідентичності повторень; може повернутись для refresh-класу) і періодичний `mt invalidate` (семантично хибний — засмічує audit trail). Оновлено: [architecture/index.md](architecture/index.md), [index.md](index.md), [architecture/overview.md](architecture/overview.md) (2 терміни глосарію), [architecture/operations.md](architecture/operations.md) (CLI-блок, `mt cleanup`, довідник ключів). ## 2026-07-12