Watch
1
0
Fork
You've already forked souveraine
0
souveraine/surfaces/quickshell/patches
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Fimeg cb3785bcbd patches: correct the queue; retire 0002 as obsolete, clear landed 0003/0004
The queue section claimed 0001-0004 were all unapplied. Verified with
git apply --check in both directions: 0003 landed as 8c434df, 0004 as
23cebc5, and 0002 can no longer apply at all.

0002 patched inThinkBlock in services/Ai.qml. That variable no longer
exists - typed segments made the think-fence collision impossible by
construction rather than by escaping harder. Retired, not abandoned.

0001 and 0006 were on disk and undescribed. Both now carry their
reasoning here. 0007's block records the specific installed version it
waits on, since 'needs the server first' is not actionable a month
later.

A queue is not an archive; git keeps history.
2026-08-12 14:12:26 -04:00
..
0001-resume-offer.patch shell: patches queue — agent stages, human applies 2026-08-10 23:04:59 -04:00
0006-stepup-authenticate-through-pam.patch patches: queue 0006, step-up authenticates through PAM 2026-08-12 12:20:11 -04:00
0007-shell-render-context-occupancy-and-stop-reading-hypr.patch patches: queue 0007, render context occupancy and stop reading hyprctl errors as cursor 2026-08-12 12:20:11 -04:00
0008-agent-surface-owned-message-delegate.patch shell: own the agent message delegate and the reasoning card 2026-08-12 13:11:19 -04:00
0009-speech-stop-and-resynthesize.patch patches: queue 0009 speech stop/resynthesize; unblock 0008 2026-08-12 13:55:35 -04:00
README.md patches: correct the queue; retire 0002 as obsolete, clear landed 0003/0004 2026-08-12 14:12:26 -04:00

patches/

⚠ 0008 — control-row parity resolved df11bba; still needs one load. 0008-agent-surface-owned-message-delegate.patch swaps the message delegate to modules/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 df11bba five 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 — /resume brings 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: true restores the old behaviour. Explicit resume paths are unchanged. The second half is undrawn — resumeOffered fires 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. StepUpAuth called souveraine-pam-auth — a binary that was never written — and fell back to pkcheck against an action that was never shipped, so every step-up grant request was silently denied. Runs a real PamContext against souveraine-stepup, which cc541d1 now ships. Note fpc-polkit-pam.c:86 refuses every service except polkit-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 f266136 running, not merely installed. As of 2026-08-12 the box runs souveraine 0.1.r442.gfb5e9bb80cac-1, and fb5e9bb predates f266136 — edge has not rebuilt. Applied early the pill honestly shows , which looks exactly like the patch failing. The bug it fixes: ContextPressure crossed a module boundary as a positional tuple, so every consumer guessed what the second element was. The TUI guessed limit and was right; the HTTP layer named it tokens and was wrong, so the Panel printed the ceiling (250000) as the usage. Also: command -v hyprctl succeeds 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:

    • playProc ran sh -c "mpv … || ffplay …". A compound command means sh does not exec-replace itself — it forks the player and waits — so running = false SIGTERMs 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/playing split out of speaking, which could not tell ~11 s of synthesis from audible playback. speaking left 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 inThinkBlock in services/Ai.qml; grep -c inThinkBlock on 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 into config.json and segfaulted JsonAdapter::deserializeRec on 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.