- Add CalendarEvents method to recordingAPI in auth_test.go
- Add CalendarEvents method to fakeCore in handlers_test.go
Co-Authored-By: opencode <opencode@anthropic.com>
- digest queue no longer dropped on failed dispatch (retry next tick)
- collapsed reminders marked fired/rescheduled only after digest delivers
- /tools step-up gate skipped when WebAuthn is not configured (was 403 forever)
- passkey credential store rolls back memory on persist failure
- auth_test fake updated for TickTrace (branch build break)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ASstMtsZWLSRcD1Tq8T68Q
Add cron expression support for recurring reminders using robfig/cron/v3.
Changes:
- Migration #2: ALTER TABLE reminders ADD COLUMN cron TEXT + next_fire_ts INTEGER
- Reminder struct: add Cron and NextFireTs fields
- scanReminder helper extracts full row including nullable cron
- CreateReminder: accept optional cron param, store next_fire_ts = fire_ts
- DueReminders: query on next_fire_ts instead of fire_ts
- RescheduleReminder: new method — parse cron, compute next fire, update
next_fire_ts or mark fired if no more valid times
- Dispatcher: call RescheduleReminder for cron reminders, MarkReminder for
one-shots (preserving existing behavior for ID=0 digest skip)
- ReminderCompleter interface: add RescheduleReminder method
- storeAPI adapter: forward RescheduleReminder
- All callers updated: CreateReminder signature includes cron param
- Tests: TestRecurringReminder (store), TestDispatchRecurringReminderReschedules
- Existing tests updated for new signature
Add a 'scope' TEXT column (default 'homelab') to the tools table so tools
can be namespaced by scope (e.g. "homelab:restart", "datacenter:reboot").
Backward-compat: bare name defaults to "homelab" scope.
Changes:
- Migration #1: ALTER TABLE tools ADD COLUMN scope
- store.Tool: add Scope field, update all SQL and scanTool()
- ipc.Tool DTO and request types: add Scope field
- CoreAPI interface: pass scope in ProposeTool/EnableTool
- storeAPI adapters: forward scope
- cmd/mavend/voice: pass scope (empty → homelab)
- cmd/mavweb/tools: show scope column in UI tables, hidden fields
- All tests updated for scope field
- Migration test made dynamic (startVer = len(migrations))
recordingAPI did not implement the new CoreAPI.RevertFact method
added in a02e10f, causing a build failure in auth tests.
Also adds coverage.out to .gitignore.
- handlers_test.go: first tests for cmd/mavweb (feature-ranking #2). Covers
the /tools enable/disable surface (arg parsing, error mapping, html escaping)
and the webauthn handler contracts (method guards, malformed input). 14 cases.
Verified the enable path is genuinely gated: an un-asserted call fails at the
mavend IPC boundary (Requirement(EnableTool)=AuthStepUp), so mavweb stays a
trust-nothing pass-through and core mediates.
- policy.go: DisableTool now also requires AuthStepUp. It mutates the same tool
allowlist as EnableTool and is a lever to silence a security-relevant tool;
gating allowlist mutation uniformly beats a split rule. ProposeTool stays
maven-callable (no passkey). Corrects the stale api.go comment that claimed
all three gated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes the three in-flight open items and fixes the away-fallthrough bug.
Item 7 — passkey step-up (WebAuthn):
- internal/webauthn: ES256/P-256 register + assert with real ecdsa signature
verification, minimal CBOR/COSE decode, PasskeySession (L2→L3 on assert,
decays after TTL). Drop the RS256 offer we can't verify (register-ok/
assert-fail trap). Verify rpIdHash + UP/UV flags in FinishAssertion — UV is
the step-up gesture. Round-trip test with negative cases (tampered sig,
missing UV, wrong origin).
- cmd/mavweb: /auth/passkey enroll+assert page (the only surface that can do
a WebAuthn gesture) + the four begin/finish endpoints. Without this the
daemon's PasskeySession swap leaves /tools enable permanently blocked.
- daemon wires PasskeySession as the auth Session + srv.StepUp; policy gates
MethodAssertStepUp at AuthRead.
Item 5 — tools page: DisableTool through store/ipc/client/wire; /tools grows a
disable action and a link to the passkey page. Lifecycle test.
Item 6 — note RAG: PhraseQuery on the phraser (LLM-composed answer over top-k
notes, raw-notes fallback); IntentQuery routes through it. Stub returns a
deterministic summary.
Item 2 — away-fallthrough: on ErrVoiceNoSession the dispatcher now reroutes
through the AWAY table (sev3→ntfy, sev4→telegram-repeat-til-ack, sev≤2→drop)
instead of silently dropping / mis-routing to the present-list remainder.
Covers DispatchNudge + DispatchReminder. 4 tests.
Also: re-add ProposeTool to CoreAPI (dropped in a comment rewrite), fix
missing imports + a duplicate block left mid-edit, drop dead AssertStepUpFunc,
gitignore /mavcaldav.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>