Pause capture on lock screen and configurable idle state #70
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
nsaspy/local-recall!70
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "agent/issue-18-lock-idle-state"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #18.
Problem and scope
Implement authoritative lock-screen and configurable idle-state handling without creating a second capture/privacy state machine. Lock state is a security boundary: startup, unknown state, source failure, reconnect, and stale unlock evidence all fail closed.
Lock-source architecture
org.freedesktop.login1.Sessionon the local system D-Bus.GetSession, validates the returned object path, and queriesLockedHintusing bounded fixed-argumentbusctl --systemcalls without a shell.LockedHint=falseis required to establish unlocked state. A target-sessionLocksignal fails closed immediately; anUnlocksignal alone never authorizes capture and becomes unknown until a freshLockedHint=falseobservation is obtained.Idle-source architecture
idleand opt-in normalizedidle.secondsmetadata.xprintidleinvocation with no shell, bounded output/time/value validation, and clean unavailable/malformed results.Lock vs idle precedence
Lock is stronger than idle:
Startup and daemon restart while locked
Session-safety preflight runs before lifecycle recording authorization. Startup begins with policy lock asserted and capture blocked until current lock state is known. Already-locked and unknown startup states enter paused/non-capturing behavior, so restart while locked has no transient capture window. Lock resolution remains mandatory even if idle handling is disabled or unavailable.
Generation and cancellation semantics
session_lockedpolicy gate; changing lock state advances policy generation.Rapid race handling
Coverage includes capture authorized -> lock -> unlock -> stale persistence callback, lock during downstream processing, duplicate transitions, and old-generation callbacks after resume. Stale frames cannot persist or continue to OCR/index/summarization/provider boundaries after invalidation.
Configuration impact
Added immutable validated
capture.idlesettings:enabled(default false)pause_capture(default true)threshold_seconds(> 0, <= 24h; exact threshold is idle)resume_behavior(immediate,active-grace,manual)active_grace_seconds(bounded <= 5m)max_observation_age_seconds(bounded <= 5m)Active-grace duration uses an injected monotonic clock. Restrictive reloads reclassify the current observation and invalidate authorization immediately where required. More-permissive reloads cannot revive an old generation. The configuration change is additive/defaulted under the current schema.
Audit and status
Session-safety audit/status objects contain only normalized control state, fixed source IDs/revisions, generation, timestamps, threshold/health, and fixed failure codes. Raw D-Bus payloads, ActivityWatch payloads, usernames, titles, domains, command lines, OCR, screenshots, and tokens are excluded. Existing closed lifecycle audit transition mappings for lock/unlock/idle/active are reused.
Security boundaries
TDD evidence
RED:
e9b0cb6c14718dae8ee6b91f3f413a28826ebc57.31635438606passed formatting, Ruff, and ShellCheck, then strict Pyright failed specifically because the new typedlocal_recall.session.safetyproduction API did not exist.GREEN:
31639771804passed the exact canonical./scripts/checkbefore committing the production tree.92ea3ac6533c6c33b5f590ffb4e8a4e46bd4eccdpassed normal CI run31639943187:0 errors, 0 warnings, 539/539 tests passed, 8 failure modes verified, repository policy checks passed, plus the repository's current security scan layers.Acceptance-criteria mapping
LockedHintqueried before recording can begin.Known limitations
LockedHintcorrectness depends on the desktop/session locker cooperating with logind; Local Recall responds to missing/uncertain truth by failing closed.xprintidle; absence affects idle fallback only, never lock blocking.A successful unlock or active-idle observation does not resurrect previously authorized work. New capture requires fresh lifecycle and policy authorization.
Missing idle support does not weaken lock-screen blocking.