Files
claude 85a3397bf4 Cancel a reminder by voice, and honour a refusal (V-719)
reminder_cancel.go is a stateful pre-route resolver ahead of a parked
clarification and the statistical cascade. It accepts only an addressed
command-position imperative plus the reminder or alarm noun, so questions,
reported speech, past-tense reports and prohibitions establish no mutation
authority. Subject terms keep negation and quantity, and a parsed time
passes the same resolved-hour gate as capture.

One match cancels through the typed IPC method. Several are stored as
session candidates in the spoken order, capped at five, and only a whole
affirmative ordinal consumes that list: re-querying on the follow-up would
let a state change move the ordinal underneath him. No match, an unread
time, a spent ordinal and an ambiguous delivery result are all explicit
no-ops.

command_prohibition.go is the first mutation boundary in a turn. A direct
prohibition clears the three confirmation slots under their shared mutex,
so a later bare "да" cannot revive authority he has just revoked. A parked
clarify question is not authority and survives, suspended and repeated.
refusesCommand is the same belt at the executor entry points, checked
against the original utterance so a model rewriting Slots.Text cannot get
around it.

The rung is named in preRouteLadder, so /trace records whether it won or
declined on every surface.

--no-verify: master is the working branch this session by the owner's call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 17:19:25 +04:00

220 lines
10 KiB
JSON

{
"schema_version": 1,
"name": "assistant_workday",
"description": "One continuous, deterministic workday through Maven's real conversation pipeline. It proves note capture and grounded high-overlap recall; a reminder that remains uncommitted while Maven clarifies its day, then survives a reported-action no-op, is cancelled exactly once, and stays cancelled on a repeated command; task capture, listing, completion, and a second live task; and the same calendar fact read through both agenda and composed day-plan sources. Store assertions are primary: every mutation and no-op pins exact row count, identity, lifecycle state, provenance, and fake-clock time.",
"start": "2026-08-15T08:00:00+04:00",
"script": [
{
"match": "запомни: запасной ключ лежит",
"route": "[{\"intent\":\"note\",\"text\":\"запомни: запасной ключ лежит в синей коробке\"}]"
},
{
"match": "запасной ключ лежит в синей коробке",
"route": "[{\"intent\":\"query\",\"text\":\"запасной ключ лежит в синей коробке?\",\"source\":\"recall\"}]"
},
{
"match": "я отменил напоминание",
"route": "[{\"intent\":\"chat\",\"text\":\"я отменил напоминание про молоко\"}]",
"reply": "{\"response\":\"Поняла.\",\"mood\":\"neutral\"}"
},
{
"match": "",
"route": "[{\"intent\":\"chat\",\"text\":\"\"}]",
"reply": "{\"response\":\"Поняла.\",\"mood\":\"neutral\"}"
}
],
"steps": [
{
"at": "08:00",
"note": "Capture only the dictated body as one durable note: the command frame is not memory, and no task, reminder, or fact is created.",
"say": "запомни: запасной ключ лежит в синей коробке",
"expect_no_send": true,
"expect_store": {
"notes": { "count": 1, "rows": [{ "id": 1, "at": "08:00", "text": "запасной ключ лежит в синей коробке", "source": "tap:voice" }] },
"tasks": { "count": 0 },
"reminders": { "count": 0 },
"facts": { "count": 0 }
}
},
{
"at": "08:01",
"note": "Recall reads the stored note and does not create a second row.",
"say": "запасной ключ лежит в синей коробке?",
"expect_reply_contains": ["синей коробке"],
"expect_no_send": true,
"expect_store": {
"notes": { "count": 1, "rows": [{ "id": 1, "text": "запасной ключ лежит в синей коробке", "source": "tap:voice" }] }
}
},
{
"at": "08:02",
"note": "A clock without a day is not a committed reminder. Maven asks, and the reminder table remains empty.",
"say": "напомни купить молоко в 10:00",
"expect_reply_contains": ["В какой день"],
"expect_no_send": true,
"expect_store": {
"reminders": { "count": 0 }
}
},
{
"at": "08:03",
"note": "The clarification completes the parked request against the fake clock and creates exactly one pending reminder.",
"say": "сегодня",
"expect_reply_contains": ["10:00"],
"expect_no_send": true,
"expect_store": {
"reminders": { "count": 1, "rows": [{ "id": 1, "fire_at": "10:00", "text": "купить молоко", "status": "pending" }] }
}
},
{
"at": "08:04",
"note": "A first-person report is not another cancellation command and cannot mutate the pending row.",
"say": "я отменил напоминание про молоко",
"expect_reply_contains": ["Поняла"],
"expect_no_send": true,
"expect_store": {
"reminders": { "count": 1, "rows": [{ "id": 1, "fire_at": "10:00", "text": "купить молоко", "status": "pending" }] }
}
},
{
"at": "08:05",
"note": "The addressed imperative cancels that exact durable reminder in place.",
"say": "отмени напоминание про молоко",
"expect_reply_contains": ["отменила напоминание", "купить молоко"],
"expect_no_send": true,
"expect_store": {
"reminders": { "count": 1, "rows": [{ "id": 1, "fire_at": "10:00", "text": "купить молоко", "status": "cancelled" }] }
}
},
{
"at": "08:06",
"note": "Repeating the cancellation is an explicit no-op: no replacement row and no resurrection.",
"say": "отмени напоминание про молоко",
"expect_reply_contains": ["ожидающих напоминаний нет"],
"expect_no_send": true,
"expect_store": {
"reminders": { "count": 1, "rows": [{ "id": 1, "fire_at": "10:00", "text": "купить молоко", "status": "cancelled" }] }
}
},
{
"at": "08:07",
"note": "An explicit task marker creates one open task, not a note.",
"say": "добавь в задачи настроить бэкапы",
"expect_reply_contains": ["настроить бэкапы"],
"expect_no_send": true,
"expect_store": {
"notes": { "count": 1 },
"tasks": { "count": 1, "rows": [{ "id": 1, "created_at": "08:07", "text": "настроить бэкапы", "source": "tap:voice", "status": "open" }] }
}
},
{
"at": "08:08",
"note": "Listing is read-only and returns the live task without duplicating it.",
"say": "какие у меня задачи?",
"expect_reply_contains": ["настроить бэкапы"],
"expect_no_send": true,
"expect_store": {
"tasks": { "count": 1, "rows": [{ "id": 1, "text": "настроить бэкапы", "status": "open" }] }
}
},
{
"at": "08:09",
"note": "Naming the task moves the same row forward to done and records who resolved it.",
"say": "закрой задачу настроить бэкапы",
"expect_reply_contains": ["настроить бэкапы"],
"expect_no_send": true,
"expect_store": {
"tasks": { "count": 1, "rows": [{ "id": 1, "created_at": "08:07", "text": "настроить бэкапы", "source": "tap:voice", "status": "done", "resolved_at": "08:09", "resolved_by": "tap:voice" }] }
}
},
{
"at": "08:10",
"note": "A second task remains live for the rest of the workday while the completed row remains durable history.",
"say": "добавь в задачи отправить отчёт",
"expect_reply_contains": ["отправить отчёт"],
"expect_no_send": true,
"expect_store": {
"tasks": { "count": 2, "rows": [
{ "id": 1, "text": "настроить бэкапы", "status": "done", "resolved_by": "tap:voice" },
{ "id": 2, "created_at": "08:10", "text": "отправить отчёт", "source": "tap:voice", "status": "open" }
] }
}
},
{
"at": "08:11",
"note": "A fully specified reminder commits directly and coexists with the cancelled history row.",
"say": "напомни сегодня в 12:00 размяться",
"expect_reply_contains": ["12:00"],
"expect_no_send": true,
"expect_store": {
"reminders": { "count": 2, "rows": [
{ "id": 1, "fire_at": "10:00", "text": "купить молоко", "status": "cancelled" },
{ "id": 2, "fire_at": "12:00", "text": "размяться", "status": "pending" }
] }
}
},
{
"at": "08:12",
"note": "A calendar poll contributes one exact env fact at the event instant.",
"arrive": {
"source": "poll:caldav",
"as_of": "11:00",
"fact": {
"key": "calendar_event_20260815_Планёрка",
"value": "Планёрка @ 11:00-11:30",
"kind": "env"
}
},
"expect_events": ["calendar_event_20260815_Планёрка"],
"expect_no_send": true,
"expect_store": {
"facts": { "count": 1, "rows": [{ "id": 1, "at": "11:00", "kind": "env", "key": "calendar_event_20260815_Планёрка", "value": "Планёрка @ 11:00-11:30", "source": "poll:caldav", "confidence": 1.0 }] }
}
},
{
"at": "08:13",
"note": "The agenda source reads the calendar fact without changing any durable state.",
"say": "что у меня сегодня?",
"expect_reply_contains": ["Планёрка"],
"expect_no_send": true,
"expect_store": {
"facts": { "count": 1, "rows": [{ "id": 1, "key": "calendar_event_20260815_Планёрка", "source": "poll:caldav" }] },
"tasks": { "count": 2 },
"reminders": { "count": 2 }
}
},
{
"at": "08:14",
"note": "The daemon day-plan seam composes the same calendar fact with the still-pending reminder; cancelled reminders stay out.",
"say": "какие планы на сегодня?",
"expect_reply_contains": ["Планёрка", "размяться"],
"expect_reply_lacks": ["купить молоко"],
"expect_no_send": true,
"expect_store": {
"notes": { "count": 1, "rows": [{ "id": 1, "text": "запасной ключ лежит в синей коробке" }] },
"tasks": { "count": 2, "rows": [
{ "id": 1, "text": "настроить бэкапы", "status": "done" },
{ "id": 2, "text": "отправить отчёт", "status": "open" }
] },
"reminders": { "count": 2, "rows": [
{ "id": 1, "text": "купить молоко", "status": "cancelled" },
{ "id": 2, "text": "размяться", "status": "pending" }
] },
"facts": { "count": 1, "rows": [{ "id": 1, "key": "calendar_event_20260815_Планёрка", "value": "Планёрка @ 11:00-11:30" }] }
}
},
{
"at": "08:15",
"note": "A normal tick after the session remains silent; durable assistant state does not authorize an unsolicited message.",
"tick": true,
"expect_no_send": true,
"expect_store": {
"notes": { "count": 1 },
"tasks": { "count": 2 },
"reminders": { "count": 2 },
"facts": { "count": 1 }
}
}
]
}