| Filename | Latest commit message | Latest commit date |
|---|---|---|
The queue section claimed 0001-0004 were all unapplied. Verified with git apply --check in both directions: 0003 landed as |
||
| .. | ||
| 0001-resume-offer.patch | ||
| 0006-stepup-authenticate-through-pam.patch | ||
| 0007-shell-render-context-occupancy-and-stop-reading-hypr.patch | ||
| 0008-agent-surface-owned-message-delegate.patch | ||
| 0009-speech-stop-and-resynthesize.patch | ||
| README.md | ||
patches/
⚠ 0008 — control-row parity resolved
df11bba; still needs one load.0008-agent-surface-owned-message-delegate.patchswaps the message delegate tomodules/souveraine/agent/AgentMessage.qml. When it was queued, that file carried none of the vendor's seven controls (ii-base/.../aiChat/AiMessage.qml:196-308), so applying it would have silently removed all seven — a parity regression wearing the costume of a swap.As of
df11bbafive are carried (Speak, Re-synthesize, Copy, Show-raw, Delete) and two are dropped deliberately, which is a decision and not an oversight:
- Regenerate — the conversation is forward-only.
Ai.regenerate()is already a no-op returning advice, so the button's only behaviour was to explain it did nothing.- Edit — there is no in-place edit. The vendor's wrote to a local array the server never sees, so the message read back was not the message held.
Delete is armed, not immediate.
removeMessage()splices two local arrays and leaves the server transcript untouched —/resumebrings the message straight back — so it is a view filter wearing a delete icon. The armed row says so in words.Apply 0009 first or together: the re-synthesize control prefers
Speech.resynthesize(), which 0009 adds. Without it the control degrades to the legacy cache-hitting path rather than breaking, but that path cannot actually re-synthesize.Lint: 0 syntax findings; every other finding traces to one directory import qmllint cannot resolve, proven environmental because
AiChat.qml— live in the running shell — produces the identical failure. Nothing has loaded it.
Staged shell changes that are not applied to the tree.
Why this directory exists
~/.config/quickshell/souveraine/*.qml are symlinks into this repo, and
quickshell reloads on write. So editing a file here edits the running shell,
immediately. When the agent is the one editing, that means an edit can take
down the process the agent's own turn is running inside — and a shell that
fails to compile does not come back on its own (see 29ec9fe: one bad root type
failed the whole qs.services module).
So the rule is: the agent writes patches, the human applies them. The
reload happens on a human's beat, when nothing is in flight, with a known-good
tree one git checkout away.
Applying
cd ~/Projects/souveraine
git am surfaces/quickshell/patches/0001-....patch
# then reload the shell yourself and watch it come up
Verify before trusting:
cd surfaces/quickshell
./deploy.sh
timeout 40 qs -c souveraine 2>&1 | grep -E "ERROR|Configuration Loaded"
If it does not come up, git reset --hard HEAD~1 and the patch is just a file
again.
Discipline
- One patch, one behaviour. Reviewable in a sitting.
- The patch's commit message says what it changes and what it deliberately leaves alone.
- A patch is untested against a running shell unless its notes say otherwise. Say which: verified / reasoned / untested.
- Applied patches get deleted from this directory in the same commit that applies them. This directory is a queue, not an archive — git keeps history.
In the queue
Status below is from git apply --check in both directions, not from
memory: forward-applies means pending, reverse-applies means already landed.
Run it before trusting this list — a queue file is a claim with a shelf life.
for p in surfaces/quickshell/patches/000*.patch; do
git apply --check "$p" 2>/dev/null && echo "$p PENDING"
git apply --check --reverse "$p" 2>/dev/null && echo "$p LANDED"
done
Apply order. 0009 before or with 0008; 0007 last, after the server upgrade. The rest are independent.
-
0001 — resume offer. Pending since 2026-08-10. The agent-established hook offers the latest thread instead of silently attaching it; default becomes start-fresh,
ai.autoResume: truerestores the old behaviour. Explicit resume paths are unchanged. The second half is undrawn —resumeOfferedfires and nothing renders it, so with no UI the behaviour is still correct (doing nothing starts fresh) but the affordance to continue is missing. -
0006 — step-up authenticates through PAM. Rook's, not mine.
StepUpAuthcalledsouveraine-pam-auth— a binary that was never written — and fell back topkcheckagainst an action that was never shipped, so every step-up grant request was silently denied. Runs a realPamContextagainstsouveraine-stepup, whichcc541d1now ships. Notefpc-polkit-pam.c:86refuses every service exceptpolkit-1, so step-up is password rather than finger until that check widens — one line, and a security decision that is Casey's. -
0007 — render context occupancy; stop reading hyprctl errors as cursor. Blocked on the server. Needs
f266136running, not merely installed. As of 2026-08-12 the box runssouveraine 0.1.r442.gfb5e9bb80cac-1, andfb5e9bbpredatesf266136— edge has not rebuilt. Applied early the pill honestly shows—, which looks exactly like the patch failing. The bug it fixes:ContextPressurecrossed a module boundary as a positional tuple, so every consumer guessed what the second element was. The TUI guessedlimitand was right; the HTTP layer named ittokensand was wrong, so the Panel printed the ceiling (250000) as the usage. Also:command -v hyprctlsucceeds on the phone (installed as a Lua-eval shim), so it runs under viewtop, fails, and its error text is captured as the cursor position — the probe tested whether the tool was installed, not whether it answered. -
0008 — owned message delegate. Parity resolved by
df11bba; see the header. Apply with or after 0009. -
0009 — speech: make stop actually stop, and re-synthesis actually re-synthesize. Three defects that all present as audio piling up and not being callable back:
playProcransh -c "mpv … || ffplay …". A compound command means sh does not exec-replace itself — it forks the player and waits — sorunning = falseSIGTERMs sh while the player keeps sounding as an orphan. Reproduced directly: wrapper died, child survived. Now mpv is invoked with no shell, so the pid quickshell holds is the pid making noise.resynthesize()added.speak()opens with a cache check keyed on the text, and re-synthesis is by definition the same text — so the one control that exists for "that came out wrong" was guaranteed to replay the identical broken audio.synthesizing/playingsplit out ofspeaking, which could not tell ~11 s of synthesis from audible playback.speakingleft untouched.
Lint identical before and after — introduced nothing. No audio has been played through it.
Recently closed
- 0002 — think-fence collision. Retired 2026-08-12, obsolete not abandoned.
It patched
inThinkBlockinservices/Ai.qml;grep -c inThinkBlockon that file now returns 0. Typed chat segments (0003) made the collision impossible by construction — a sensor firing mid-reasoning lands in its own segment and cannot close a fence, because there is no fence. Escaping harder was the right fix for the string design; the design changed underneath it. A queued patch that can no longer apply reads as "not done yet" forever, so it goes. - 0003 — typed chat segments + tool cards. Landed as
8c434df. - 0004 — keep typed segments QML-compatible. Landed as
23cebc5. - 0005 — config: never store a null option. Applied and committed as
f7e0e51. Null-valued options serialised intoconfig.jsonand segfaultedJsonAdapter::deserializeRecon the next launch — the session that wrote the option ran fine, every launch after it died ~10 s in. Replaced with tristate strings (auto/on/off), booleans still honoured. Verified live: shell loads clean, no nulls written back. - 0005 (earlier) — mount the agent island. Retired by
013a06a; the island left the bar to sit beside chat (2179b62). The number was reused.