Watch
1
0
Fork
You've already forked souveraine
0
Commit graph souveraine/surfaces/quickshell/modules
Author SHA1 Message Date
Fimeg
d7965a57fd two swipes, one progress; home is zone 0; pocket is a belief 2026-08-05 19:16:41 -04:00
Fimeg
6c0730a790 the sheet scrims its own window, not the screen 2026-08-05 16:43:14 -04:00
Fimeg
0e7dec53d1 the app scales into multitasking; pill has two destinations 2026-08-05 16:34:51 -04:00
Fimeg
277a0d2b32 dock lives on zone one; short swipe multitasks, big swipe goes home 2026-08-05 16:17:47 -04:00
Fimeg
c3f998f17a move is a mode: grab, drag, done 2026-08-05 15:35:40 -04:00
Fimeg
b0688bc30b split chooser, home reaches the compositor, idle-inhibit comment was backwards 2026-08-05 14:52:48 -04:00
Fimeg
f7eba9f658 hold power for a device menu; usb-c state shown, not faked 2026-08-05 14:37:56 -04:00
Fimeg
bf8bc013ef three-finger tap opens a window sheet, not the overview 2026-08-05 14:12:22 -04:00
Fimeg
3aea8398a9 shell: intent wins the settle window, and a swap is a request for a keyboard
Two gaps in the owner-change handling, both found on device.

The push at adopt time can lose a race. osk-switch sleeps 0.3s before
its deliberate SetVisible(true), and stevia self-shows once it has
finished coming up - both land after the shell has spoken. Measured:
adopt+hide 07:37:51, Visible=true 07:37:52, leaving oskOpen=false with a
keyboard on the screen. Re-assert when the settle window closes so the
last speaker is not the winner.

And the oskSwap gesture never recorded that a swap means the user wants
a keyboard, so osk-switch's re-show and the shell's stale false were
racing with nothing to arbitrate them. Declare the intent first.
2026-08-05 07:41:02 -04:00
Fimeg
d7a04f27d5 shell: an owner change is not a visibility event
sm.puri.OSK0 is a name, not a process. Boot, a crash-restart and an
osk-switch swap each put a fresh keyboard behind it, and the visibility
monitor mirrored the newcomer's opening claim into oskOpen as though the
user had asked for a keyboard. Measured: shell up 03:03:38, self-showed
at 03:03:43, nobody near the phone.

Track the bus owner - gdbus already prints it and the 'Visible' filter
was throwing it away - and on a change push oskOpen at the new owner
instead of pulling state out of it. A process that just started has no
history; the shell is the continuity of intent across the keyboard's
lifetime.
2026-08-05 07:34:53 -04:00
Fimeg
80cb4b289d shell: read the instance file synchronously, or it is empty when asked
FileView loads async, so text() was still empty when onReadyChanged read it
once to decide whether this is a new session. It fell through to the unset
env var and persisted "" — the same bug, reached by a different route.
Verified on device: the stored signature now matches viewtop.instance.
2026-08-04 19:25:59 -04:00
Fimeg
95dd21b998 shell: take the instance signature from viewtop, not from Hyprland's env
HYPRLAND_INSTANCE_SIGNATURE is unset under viewtop, so this compared "" to
"" and isNewHyprlandInstance was false on every start. It gates
lock.launchOnStartup, which has therefore never fired once under viewtop,
and both Idle.qml copies read it as well.

viewtop publishes viewtop.instance beside its control socket — pid plus
startup nanos, different every start. Read that first, fall back to the env
var so a Hyprland session (the laptop is still one) keeps working, and
treat "neither" as the session continuing, which re-locks rather than
assuming a fresh boot.
2026-08-04 19:19:31 -04:00
Fimeg
f320a0221d shell: answer to the ipc target sessiond actually calls
Action::Overview shells out to `ipc call overview toggle`. The only handler
here was `search`, so that call reached nothing and the three-finger tap
did nothing, without an error anyone would see.

It has been invisible from the device because the shipped sessiond has no
`gesture` verb yet and refuses the op long before the executor runs, so
only the first half of the break was observable.

This makes the existing binding reach the surface it already names. What
the tap should raise is TASK-55 Q1 and is not decided here.
2026-08-04 15:02:34 -04:00
Fimeg
44a54330c2 shell: mission control draws the cards it was already building
The panel, its mask and the loader all moved to overviewOpen ||
missionControlOpen when mission control landed; the Column holding them
did not. So the second-stage pill swipe raised a panel whose entire
contents were invisible — WindowOverview instantiated, laid out, and never
shown.

Search stays overview-only: mission control takes no keyboard focus on
purpose, so a field there is one you can see and cannot use. Outside-tap
now clears both states, because with no focus grab that tap is mission
control's only way back.
2026-08-04 14:43:35 -04:00
Fimeg
356cfc6462 overview: viewtop has workspaces; the header said it did not 2026-08-04 09:32:03 -04:00
Fimeg
cc4bb83573 shell: the overview arrives as one surface, and mission control finally lands
Everything drove off a visible/not-visible flag, so the cards appeared
rather than the overview opening. One shared `progress` now: the strip
slides 24px, each card takes its own share of it staggered by index and
capped at the fifth, and scale runs 0.86 to 1.0 — the reference shell's
numbers, driven from the same clock instead of a timer per card. The cap
is what stops the tenth card starting half a second after the first,
which reads as loading rather than opening.

This is also SHELL-ECOSYSTEM's stated model, taken from Phosh: state
gates visibility, never the reverse.

`missionControlOpen` has been set by the pill's second-stage swipe since
July and consumed by NOTHING — TASK-14 records the Auxo-like card
surface it was meant to raise as never built. WindowOverview is that
surface. The state reaches something now instead of being set and
dropped.

Mission control is the cards alone: no search, and no keyboard focus,
because it is "switch to what is running" and not "find something" — and
taking the keyboard would summon the OSK over a surface with no field.
2026-08-03 22:18:43 -04:00
Fimeg
8c41f45420 shell: the overview swipes sideways, and stops rejecting its own buffer
Two faults in the first cut.

cacheBuffer was height * 2, and height is -1 until the first layout
pass, so ListView refused it outright and said so on every open. Clamped
at zero.

The strip was vertical. TASK-14 asks for "horizontally swiped live app
cards" and the reference shell's carousel says the same thing in its own
comment — the whole strip slides in horizontally. On a phone the thumb
travels sideways, and a vertical list fights the flick-up that dismisses
a card, so the two gestures were competing for the same axis. Horizontal
with snap-one-item, cards filling the viewport.
2026-08-03 19:15:18 -04:00
Fimeg
fdb0acfdce shell: the overview shows windows, because there are no workspaces here
OverviewWidget draws a grid of workspaces and places windows in them by
Hyprland coordinates — HyprlandData.windowList, monitorData,
Hyprland.monitorFor. Under viewtop none of it resolves, and more to the
point viewtop has no workspaces at all: one space, a tiling layout. The
old overview could not be repaired by repointing it at another data
source, because the thing it draws does not exist. It rendered an empty
frame, which reads as the overview being broken.

WindowOverview lists what does exist. Cards from
ToplevelManager.toplevels — the same list the dock and TaskbarApps
already read, so there is one idea of what is open — each holding a
live ScreencopyView of one window, which only became possible when the
compositor started serving a per-window capture source; until then a
card could have shown nothing but the screen it was covering.

The motion is the reference shell's, read out of
overview_window_card.dart rather than invented: stagger at index * 45 ms
capped at the fifth card, intro scale 0.86 to 1.0, dismiss past 32% of
the card height, 56 px of downward rubber-banding, settle under 200 ms.
The cap is the part worth keeping — without it the tenth card starts
half a second after the first and the overview feels like it is loading
rather than opening.

Captures run only while the overview is up. A live capture per window is
a render of that window every frame, and leaving them going behind a
closed overview is battery spent drawing what nobody can see.
2026-08-03 18:37:56 -04:00
Fimeg
c21bd1d7d9 shell: stop gating the dock on a flag the keyboard flaps
Suppressing the dock whenever oskOpen was true, above effectivePinned so
it applied in every state, hid the dock permanently on the device.

oskOpen is not "the keyboard is on screen". GlobalStates' own comment
says squeekboard hides itself whenever input-method focus drops and that
a hold re-asserts it, and the journal shows exactly that: self-showed /
self-hid every couple of seconds, settling at Visible=true with no
keyboard in front of the user. Gating a persistent surface on a flag
that flaps turns a cosmetic overlap into a dock nobody can reach.

The empty-desktop check keeps its oskOpen term, where it always was: a
spuriously-true flag there costs a reveal that was cosmetic anyway,
which is a different price from hiding a pinned dock.

The real signal is the keyboard's exclusive zone, which the compositor
already applies — an unpinned dock declares zone 0 and is placed above
the keyboard for free, the same mechanism that fixed the pill. The
pinned case, where both reserve space and the reservations stack, wants
fixing where the zones are arbitrated.
2026-08-03 17:17:01 -04:00
Fimeg
ca44b0be2a shell: the keyboard owns the bottom edge, and nothing measures it
Two bugs with one cause — the bottom edge was being reasoned about
twice, by hand, against a compositor that is gone.

The rail set ExclusionMode.Ignore (exclusive zone -1: ignore what
everyone else reserved, anchor to the whole screen) and then computed
its own lift from the keyboard's height, probed by shelling out to
`hyprctl -j layers`. Under viewtop there is no hyprctl, so every probe
threw a JSON.parse on empty output and logged it in a loop every second
or two, forever, while the margin stayed at a hardcoded fallback
measured against a keyboard that is not the one running. A 200px
fallback against some other height is exactly "the pill spawns in the
middle of the keyboard". Zone 0 with Normal — the idiom SidebarRight and
ReloadPopup already use — reserves nothing and respects what others
reserved, so the compositor anchors the rail to the top of the
keyboard's exclusive zone. Correct at any height, any rotation, across a
swap, with nothing to go stale. The probe, its retry timer and
probeOskHeight() are deleted rather than ported: a second measurement of
a number the protocol already carries is what this class of bug is made
of.

The dock consulted oskOpen only in its empty-desktop branch, below
effectivePinned, so a PINNED dock ignored the keyboard and sat under it.
DockManifest.dockState() has always reported "suppressed-by-osk" and
_blockReason() has always refused mutations with "osk-open" — the
manifest promised a suppression the dock never performed, so the agent's
view of the screen and the screen disagreed. The check moves above
pinning and applies in every state, staying below dockRevealPulse
because an explicit reveal is the one thing that should outrank the
keyboard.

Verified on the phone: the probe loop is gone from the journal. The
resulting pill and dock positions want eyes on the glass.
2026-08-03 16:53:06 -04:00
Fimeg
266af98a99 sessiond: double-tap-to-wake wakes, and the volume keys work again
Two things that worked under Hyprland and stopped when viewtop took the
session, both for the same reason: the binding lived in hyprland.lua and
the daemon was never in the path.

dt2w: note_input recorded the wake and returned Restore, which is
brightness. So a double tap reported to the machine and the screen stayed
dark. It now returns Unblank first — the brightness a panel comes back at
means nothing until the panel is back. Only for the deliberate wakes
(DoubleTapToWake, Squeeze) and only when the panel is actually dark. The
power button is excluded on purpose: apply_gesture already wakes on its
resolved tap, and emitting a second unblank here is precisely how the
wake loop happened in the compositor this afternoon.

Volume: Action::Volume through the executor table, per §12 — a small
daemon reading a signal and calling wpctl is the eighth blind actor. It
fires on the DOWN edge rather than from a recognised gesture, because
BUTTON_MULTI_TAP_WINDOW is 300ms and a volume key that lags a third of a
second behind the press feels broken. The recogniser still sees the
edges, so a future binding table gets volume hold-to-ramp without this
changing.

Shell: HyprlandData did a bare JSON.parse on hyprctl output, which throws
on every refresh when there is no hyprctl — six exceptions a pass, and
every consumer of monitorData.scale got undefined. That is why the region
selector rendered as a sliver: the geometry was not wrong, it was NaN.
Absence is now a latched state, and RegionSelection/OverviewWidget fall
back to screen.devicePixelRatio. Hyprland stays preferred where it exists.

105 tests.
2026-08-02 18:28:49 -04:00
Fimeg
94988138b4 lock hint: resolve the seat's session, and replay the report
LockedHint was never set on this device, so sessiond's `locked` (which
comes from logind per doctrine §4) was permanently false, request_blank()
timed out LOCK_ACK_BUDGET on every blank, and the panel went dark on a
session nobody could confirm was locked. LOCK-DPMS-LESSONS §1 held in the
code and not on the glass — every blank recorded blank-without-lock.

Three faults, measured 2026-08-02:

- Session.qml wrote the hint through /session/auto, which is the caller's
  own session. The shell is not in the session that owns the seat:
  viewtop in logind 66 (seat0/tty1), qs in 70. Written to one session,
  read from another.
- lockhint.rs resolved via User.Display, which an ssh login is enough to
  point at a seatless remote session — and which then went stale when
  that session ended. Both sides now ask seat0 for its active session.
- The report was dropped outright. hasLoginctl starts false and only
  flips when a Process probe returns; secure=true landed 30s earlier, so
  the one edge that mattered hit the guard and was never retried, because
  the shell locks once at boot and never changes again. Fourth
  edge-vs-level bug after locked_ack, ChargeRate and bootBloomActive.

Verified on hardware: LockedHint now goes yes ~2s after a power tap.
2026-08-02 15:26:37 -04:00
Fimeg
5c618f1514 lock: hoist the lock out of the Config.ready loaders so a reload can adopt
PanelLoader is a LazyLoader gated on Config.ready, behind a second one.
On reload both are shut when quickshell propagates, so LazyLoader has no
item to hand its successor and the new WlSessionLock never adopts the live
compositor lock. Lock is a direct child of ShellRoot now, as the boot-order
doc already asked.

Ungated means Config may not have loaded, and touchKeypad reads false from
the adapter defaults — which would bind the desktop surface on the phone and
cannot be changed once the lock is active. The choice rides the reload too.
2026-07-31 21:25:05 -04:00
Fimeg
efe2d0d1e0 lock: adopt the session lock across a scene reload
sessiond admits shell_ready from the lease holder's own pid; the shell
carries its lock request through the reload so WlSessionLock adopts the
existing lock instead of taking the unlock branch on it.
2026-07-31 14:32:29 -04:00
Fimeg
1c90d7f76a settings: the device state machine gets a surface
TASK-08(f)/TASK-19: state, panel, evidence, confidence, per-source health, the
sensors_degraded flag and the recent decision trail were legible only through
forensic.jsonl. DeviceEvidence gains a read path (polled only while watched);
the Device page renders it. Readout only — the confidence gates are still
computed and never branched on, so controls over them would lie.
2026-07-31 13:11:43 -04:00
Fimeg
49635fb005 shell: give the subconscious event log a host
Tier 2 was written, deployed and mounted by nothing — its own header named the
gap. The chat sidebar hosts it now: ticker long-press, or the psychology
indicator by the input box, which works when no pass is running.
2026-07-31 12:51:17 -04:00
Fimeg
0b57daac06 shell: VPN quick toggle in the right panel
Deliberate, never automatic. The autonomous gate it replaces recycled the
tunnel 652 times in 90 minutes and could not be switched off, because
'nmcli connection down' fired the dispatcher that brought it back up.

Reads NM for state rather than tracking a bool. No privilege needed: polkit
already lets the seat user activate a system connection. Registered in the
ii-phone chooser as well as ii-base, or the phone overlay wins and the
delegate never appears.
2026-07-30 19:13:19 -04:00
Fimeg
15af38ae36 deploy: ship the subconscious module in the shell manifest
The ticker instantiation in AiChat referenced qs.modules.souveraine.
subconscious, but those files were absent from the deploy MANIFEST, so a
deploy left the import unresolved. Add SubconsciousTicker/EventPanel +
a qmldir mirroring the dial/selection modules.
2026-07-30 15:26:20 -04:00
Fimeg
483902a40e shell: restore the subconscious ticker to the chat column
Re-mount SubconsciousTicker in AiChat (lost in the 07-30 relocation out
of the ii tree). The view is decoupled; it just needed its host back.
2026-07-30 15:17:55 -04:00
Fimeg
25898a9d14 shell: re-home the subconscious surface from the ii tree to souveraine
The subconscious three-tier surface (SubconsciousTicker + SubconsciousEventPanel)
is Souveraine-original, not upstream ii. It lived under ii-base/modules/ii only
because it had never been re-homed, so the ii -> souveraine shell migration
silently stranded it: the files survived, but the running shell (qs -c souveraine)
never loaded them, and the feature dropped off the device.

Relocated into modules/souveraine/subconscious/, decoupled from the ii overlay
system it was riveted to:

- SubconsciousTicker: was clean of ii imports but opened the panel through the
  ii OverlayContext singleton. Now emits requestOpenPanel(); a host connects it.
- SubconsciousEventPanel: was a StyledOverlayWidget (qs.modules.ii.overlay). Now
  plain content a host instantiates; the pin/close/drag affordances were the
  overlay host's job, not the content's.

The model (services/Ai.qml) was already substrate-neutral and never moved; only
the views were stranded. GAP NAMED: no souveraine overlay host mounts these yet,
so they do not reach the glass until one exists — the ii overlay host was
intentionally not ported. The dangling ii references (AiChat, OverlayContext,
OverlayWidgetDelegateChooser) are removed.
2026-07-30 12:57:19 -04:00
Fimeg
0ef239515f surface: per-agent TTS voice + turn clock + reply-handler fix
Speech resolves voice per active agent (agents[].voice_id from the list),
with the system voice as fallback — two agents on a host need not match.
Souveraine.qml carries voice_id into the agents map and adds a turn clock
(turnStartedAt/turnElapsedMs) + a 60s agent-inventory refresh. Ai.qml
declares pendingFilePath and imports qs.modules.common.functions so
StringUtils.ttsClean no longer aborts the stream-finished handler.
2026-07-30 09:18:56 -04:00
Fimeg
147f7f28b1 Selection: size the window to the chip instead of masking a fullscreen shield
The masked-fullscreen version was completely untappable on device. Rather than
keep guessing at the mask, the window is now sized to the card and moved by
margins, so every pixel of it is the chip. Also stops an invisible fullscreen
surface sitting over the app's own selection UI.
2026-07-29 18:13:02 -04:00
Fimeg
5a643d7059 Selection: fix untappable chip and the chip that never cleared
Two bugs from the first on-device run.

The card sized itself from a layout it also centered, which resolved to zero, so
mask claimed a zero-size input region: the chip painted but no tap landed. Card
now sizes from the layout's implicit size and the background is a plain Item
child, not layout-managed.

wl-paste --watch replays the existing selection on start, so every watcher
restart (every unlock) resurrected a stale selection that could never be cleared
because the primary buffer never changed again. The first emission after a start
now only sets the baseline, and a dismissed selection is remembered so a re-read
cannot revive it.
2026-07-29 18:05:49 -04:00
Fimeg
0bebc779c6 Selection menu surface: chip that expands to actions (TASK-18)
Overlay layer following DialHost, keyboardFocus None throughout, and an input
mask limited to the card so taps elsewhere reach the app underneath. Anchors to
the pointer hint above the touch point, clamped on screen.

Chip shows a character count, never a preview: the surface floats over the app
that owns the selection and the content may be a password, so it stays ambient
and discloses nothing. Read Aloud is live via Speech; agent and reference
actions render with the reason they cannot act yet.

Adds DeviceEvidence, reporting input to the state machine's existing
Request::Input with an intent label, so a new input surface is not another
isolated actor per DEVICE-STATE-MACHINE 1. Opt-in: nothing loads or watches
until Config.options.selection.enable.
2026-07-29 17:47:20 -04:00
Fimeg
147999a918 Selection service: compositor-wide primary selection for TASK-18
Verified on blueline that Hyprland advertises primary-selection plus both
data-control managers, so wl-paste --primary --watch sees every selection with
no per-app hooks. Settles TASK-18's selection-detection question as
compositor-level; viewtop is not needed.

The protocol gives no selection rectangle, so anchor is the pointer position at
selection time. Opt-in by default: the watcher observes every highlight on the
device, including passwords, so it is killed while locked and selection text is
never persisted, logged, or trailed.
2026-07-29 17:25:34 -04:00
Fimeg
0a635ff984 lock: dismiss the boot bloom on a level, not only on an edge
bootBloomActive defaults true on every scene construction and bootDismissed
resets with it, but the only thing that cleared them was the secure EDGE. A
scene reload during an already-secure lock never moves `secure`, so nothing
cleared the bloom and the phone sat under a full-screen white overlay until the
shell was restarted. Casey hit it and reported it as "the hyprland error
screen"; `grim` returned a solid white 9KB frame, and hyprctl configerrors was
empty the whole time.

Third instance of this exact shape: locked_ack after a sessiond restart, the
ChargeRate stale-scene reload, and now this. Check the level at construction as
well as the edge.

Deliberately not a timeout — a bloom outliving its reason is a bug to locate.
2026-07-29 10:54:45 -04:00
Fimeg
5965c64781 shell: recover the phone-only edits into the repo
~/souveraine-surfaces/quickshell on the phone is not a git repo and was the
only copy of five files. Brought back verbatim:

- Gestures.qml, SystemGestureRail.qml: TASK-38 osk-swap detent (DUMP §5, §6)
- OnScreenKeyboard.qml: showOsk asks the bus instead of pgrep+sleep 1
- DockAppButton.qml, DockStack.qml: suffix-tolerant AppSearch.resolveEntry

resolveEntry itself had been added to the phone's live ~/.config/quickshell/ii
tree, which deploy.sh rsyncs from ii-base — the next deploy would have deleted
it and left the two dock callers referring to nothing. It lands in ii-base here.
2026-07-29 08:27:27 -04:00
Fimeg
53dcb40c5d dial: bind the ring origin instead of assigning it before the surface is sized 2026-07-27 08:29:44 -04:00
Fimeg
002a1a7b08 gestures: consumer + routing table, wired to the dial 2026-07-26 21:01:11 -04:00
Fimeg
bef6e6a653 dial: radial picker, haptic detents, dial IPC 2026-07-26 20:36:07 -04:00
Fimeg
be72019883 settings: write the dim value through, drop the invented clamp
Clamping the lock-screen grace to blank-1 turned a 30s dim on a 15s blank
into a 14s grace, dimming one second after you stop touching the phone.
2026-07-26 20:00:50 -04:00
Fimeg
43c1fdbc05 session: one IPC owner for target 'session', not a load-order coin flip
Session.qml and Lock.qml both registered target 'session'; quickshell keeps
whichever loads first and drops the other. Lock.qml's handler is a strict
superset, so the duplicate goes.
2026-07-26 19:04:14 -04:00
Fimeg
c7c92d2680 settings: one Brightness dimming section, one blank timeout
The page asked the same question twice because two daemons answer it, and
split the blank budget by held-vs-resting — which makes the user arbitrate a
guess the accelerometer is making. Held-ness belongs in the confidence
arithmetic as an adjustment to one budget, not as a second budget here.
2026-07-26 18:11:01 -04:00
Fimeg
4d64b4540c polkit: stop the prompt covering the on-screen keyboard
The fullscreen overlay sat above squeekboard's layer and owned the whole
screen's input region, so taps in the keyboard area hit the dialog. It now
yields the bottom third while the OSK is up. Exclusive keyboard focus was
tried and reverted — it stopped the keyboard taking touch entirely.
2026-07-26 17:39:38 -04:00
Fimeg
2b69957f18 lock: surface charge rate, and stop counting down while plugged in
UPower's ChargeType (fork, read off the charger) reaches the lock line as
fast/slow charging. Discharging with the cable in is the charger resting
between top-ups, not a drain — it now reads Charged/Plugged in.
2026-07-26 16:56:39 -04:00
Fimeg
7475fae505 osk: polkit holds the keyboard open instead of poking it once
squeekboard hides itself when input-method focus drops, so the password
field was left with no keyboard. A hold re-asserts through that and
releases on dismiss; a manual close drops the hold.
2026-07-26 16:56:34 -04:00
Fimeg
4f113ad62d shell: the dim is a grace before the lock, not a second absolute timer 2026-07-26 15:09:17 -04:00
Fimeg
70a05819e8 settings: presets instead of seconds; two ordering fixes
IdleConfig: ConfigSelectionArray presets (30s/1/2/5/10 min for the shell's
timers, 15s/30s/1/5 min/Never for the lock screen) instead of seconds
spinboxes. Nobody reasons about a lock screen in 5s increments; the policy
struct already said "iOS Auto-Lock shape". Wire values stay seconds.
Header comment corrected — hypridle no longer owns screen-off.

set_panel(false) clears pending_blank. A panel darkened by any other route
left it armed, so the next tick emitted a second Blank or hit the
blank-without-lock error path for a blank nobody was waiting on.

SetPolicy refuses dim_grace >= lock_blank_after. dim_at saturates to zero, so
the panel dimmed the instant it went idle with no lit period.

Verified by rendering the page, not by parse alone.
2026-07-26 07:24:28 -04:00
Fimeg
9ab1cfbccc settings: don't render a missing ack budget as "waits 0s"
An older sessiond has no lock_ack_budget_secs. Show the upgrade note instead of
inventing a number.
2026-07-25 18:57:48 -04:00
Fimeg
24ce6d382b shell: execute authority directives; Settings reads sessiond
SessiondBridge: handle pushed {"directive":"lock"} on the heartbeat line and
raise the lock surface. Unknown directives are console.error — a silent drop
leaves the daemon blanking unlocked when its budget expires.

SessiondPolicy: new singleton, reads/writes DeviceStatePolicy over its own
short-lived connection (not the bridge socket — that EOF is shell-death
detection).

IdleConfig: new "Lock screen (device authority)" section bound to it. SetPolicy
had zero callers, so the old spinboxes moved a JSON file the daemon never read.
Says so in the error colour when sessiond is unreachable.

New file needs a deploy.sh manifest line or the services qmldir fails whole.
2026-07-25 18:53:19 -04:00