| Filename | Latest commit message | Latest commit date |
|---|---|---|
StepUpAuth ran `souveraine-pam-auth`, else `pkcheck --action-id
org.souveraine.stepup`. Neither exists: no such binary was ever written
and no polkit action was ever shipped, so both branches failed and every
grant request was silently denied. The header also described passing a
password through SOUVERAINE_STEPUP_PASSWORD, which the code never set.
Now a PamContext against the system souveraine-stepup service, shipped by
|
||
| .. | ||
| README.md | ||
patches/
0008 and 0009 landed
93fe30a(2026-08-12). Applied by Casey, reloaded, and — for the first time in this lane — verified against a running shell.The load immediately found two faults that every prior gate had called clean (
44acb11): a missingqs.modules.common.functionsimport inThinkingCardthrowingReferenceError: ColorUtilson every reasoning segment, andsidebar.ai.fontSizeabsent from our Config override, so the vendorMessageTextBlockassignedundefinedtofont.pixelSizeon every render.Neither was reachable by lint as it was being run. The lesson is recorded in that commit and worth repeating here: lint the composed tree, not a hand-built approximation of it — a stand-in tests the stand-in. And a qmllint run that resolves nothing reports 0 findings in exactly the same voice as one that resolves everything.
Original 0008 header — kept for the two controls dropped on purpose
0008-agent-surface-owned-message-delegate.patchswapped 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 existed — and why it is being wound down
Retired 2026-08-12. The premise below was measured and found false. New shell work is edited directly; see Direct edits at the foot of this file.
The original rule was: editing a symlinked file edits the running shell, so an edit can take down the process the agent's own turn is running inside.
It cannot. Measured twice on 2026-08-12:
qs 232867 /user@1000.service/kitty-20961-2.scope
me 442470 /user@1000.service/app.slice/souveraine.service
Separate cgroups. The shell is parented to the terminal it was launched from,
not to souveraine.service. On 2026-08-12 patches 0007, 0010 and 0011 were
applied directly to the live symlinked files while an agent turn was in
flight; the shell reloaded and kept running, PID unchanged, for five hours
afterwards.
What remains true is smaller: a shell that fails to compile does not come back
on its own (29ec9fe — one bad root type failed the whole qs.services module).
That costs Casey his bar, not the agent its turn, and it is one
git checkout from repaired. It is a reason to verify, not a reason to
queue.
Direct edits — the discipline that replaces the queue
- Commit before the edit. Rollback is
git checkout <file> && ./deploy.sh. - Lint the composed tree, never a hand-built stand-in
(
/usr/lib/qt6/bin/qmllint, resolved against~/.config/quickshell/). A run that resolves nothing reports 0 findings in the same voice as one that resolves everything. - Scan the shell log after the reload —
/tmp/souveraine-shell.log, forError|error:|Unable to assign|ReferenceError. This is the step that was missing all along: on 2026-08-12 the shell had been throwingCannot assign [undefined] to inton every turn for two and a half hours and nobody read the file. - Confirm it is still alive ~10s after "Configuration Loaded." A load is not a pass — the null-config crash loads clean and dies ten seconds later.
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. 0007 last, after the server upgrade. 0001 and 0006 are independent lanes and can go whenever.
-
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. -
0010 — render a halt in her own register, not the tool's name. The Panel printed
**Halt** (advisory) — <reason>: the tool's name, its enum value, and a sentence written for the agent's body, all on the human's screen. The TUI has always rendered it as substrate voice (⟡ a pressure behind my eyes — …); this brings the Panel into line. Wording deliberately mirrorsmigraine_text()insrc/server/turn.rs, which29f8475now commits into her history — so what the human reads and what she carries into the next turn are the same sentence. If one changes, the other must. Independent of 0007/0008/0009; apply any time. Needs no server version. -
0007 — render context occupancy; stop reading hyprctl errors as cursor. Unblocked 2026-08-12 17:30. It needed
f266136running, not merely installed. The box now runssouveraine 0.1.r463.g715080bbfe45-1, started 17:26:45 against a binary installed 17:22, andgit merge-base --is-ancestor f266136 715080bpasses — so the named-field fix is in the live server. Re-verify with that one command before applying; installed is not running. (Earlier state, kept because the shape recurs: the box ran r442 =fb5e9bb, which predatesf266136, and applying early makes the pill honestly show—— indistinguishable from 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. Before building the click-through breakdown on top of this, readtasks/context-accounting-two-counters-2026-08-12.mdin memory. The pill renders the payload (what is in the model's window); the/v1/conversations/:id/tokensendpoint renders the archive (what the transcript weighs). On this conversation they differ by ~3x — 80% against a clamped 100%. Ship them side by side unlabelled and the Panel shows two numbers that contradict each other. Group the breakdown by block kind, not by role: 74% of the context is tool traffic, which per-role accounting files under "assistant" and makes it read as talkativeness.
Recently closed
-
0008 — owned message delegate. Landed
93fe30a, 2026-08-12. Applied by Casey and reloaded. The load found two faults no gate had (44acb11) — see the header. Worth keeping: the two controls dropped were decisions (regenerate is impossible on text; there is no in-place edit), so a later session should not helpfully restore them. -
0009 — speech: stop actually stops. Landed
93fe30a, 2026-08-12.sh -c "mpv … || ffplay …"is a compound command, so sh does not exec-replace itself and SIGTERM killed the wrapper while the player kept sounding as an orphan — reproduced directly. That was the back-to-back TTS slam. Shell dropped entirely; the pid held is now the pid making noise.resynthesize()bypasses the cache the old path always hit. Still unverified: no audio has been played through it. -
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.