Watch
1
0
Fork
You've already forked souveraine
0

publish: the public projection begins here

This is a projection, not a development branch. The tree above was constructed
from the internal source named below under a manifest that decides which paths
may leave, then scanned as a whole tree rather than as a series of patches, and
only then published.

Public history starts here because the history before it was not admissible,
and neither was the tree. What used to stand in this repository included a
rescue copy of another machine, a directory of phone handoffs, deployment
wired to one house, and a submodule pointing at a forge no stranger can reach.
None of that was ever the product. It stays in the private forge, which is
allowed to hold the whole working organism, and this is what was deliberately
sent out instead.

Three mechanisms produced this tree, in decreasing order of trust. A top-level
path the manifest does not name never arrives at all, which is the one that
catches directories nobody has thought of yet. Named internal files inside
admitted roots are dropped. A short, reviewed table replaces deployment
defaults that a public build must not carry -- an endpoint aimed at one LAN, a
VPN profile belonging to one phone, packaging built from one checkout path.

Everything after this commit is an ordinary publication with the same three
trailers, so a force push stops being routine and starts meaning that
something deliberate happened. The trailers bind the projection to its source
without pretending the public SHA is the private one: same lineage, different
tree, and the record says so.

Source-Sha: 8f27b1e76a8fef560a336aba18e6990713ff1047
Policy-Sha: 6b261d2f3e6e1fb19874846ba4bb1dfe15565d25b8618c1c1afba0419c101d27
Tree-Digest: 18ec3563c5e5ef9a414993a9f6734b251ff9ed3cd56eebdd6cac01e45c6e3067
This commit is contained in:
Fimeg 2026-09-04 15:55:48 -04:00
commit 8f42fc953d
1476 changed files with 238455 additions and 0 deletions

View file

@ -0,0 +1,193 @@
// Crash surfacing (TASK-05) — the other half of the supervision work in
// souveraine-shell.service. Supervision journals and restarts; this makes a
// crash *reported*: a notification through the org.freedesktop.Notifications
// pipe, which fans to banner unlocked / lock card locked / NotifyEvents.
//
// This runs inside the shell on purpose. When qs dies, systemd resurrects it
// and the fresh instance finds the new crashes.log line and announces its own
// recovery. The 8-retry give-up case has no shell to banner from — sessiond's
// fail-closed lock is that surface, not us.
//
// Emission is a real notify-send, not a shortcut into the Notifications
// singleton: the crash report exercises the same D-Bus path every other
// client uses, so a broken pipe is itself detected.
//
// Sources watched:
// 1. ~/.local/state/souveraine/crashes.log — inotify via FileView, no poll.
// 2. systemctl --user --failed — 30s timer (doc: no tight loops).
// 3. coredumpctl list tail — same 30s tick.
// Dedupe state persists in crash-reporter.state so a crash is reported once
// across shell restarts, not once per resurrection.
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property string stateDir: Quickshell.env("HOME") + "/.local/state/souveraine"
property bool started: false
// Persisted dedupe cursors.
property int crashLinesSeen: -1 // -1 = state not loaded yet
property var knownFailedUnits: []
property string lastCoredumpLine: ""
function start() {
if (root.started) return;
root.started = true;
stateFile.reload();
}
function notify(summary, body, urgency) {
Quickshell.execDetached(["notify-send", "-a", "souveraine",
"-u", urgency ?? "critical", summary, body ?? ""]);
}
function saveState() {
stateFile.setText(JSON.stringify({
crashLinesSeen: root.crashLinesSeen,
knownFailedUnits: root.knownFailedUnits,
lastCoredumpLine: root.lastCoredumpLine,
}));
}
FileView {
id: stateFile
path: root.stateDir + "/crash-reporter.state"
onLoaded: {
try {
const s = JSON.parse(text());
root.crashLinesSeen = s.crashLinesSeen ?? 0;
root.knownFailedUnits = s.knownFailedUnits ?? [];
root.lastCoredumpLine = s.lastCoredumpLine ?? "";
} catch (e) {
root.crashLinesSeen = 0;
}
crashLog.reload();
}
onLoadFailed: {
// First run: baseline everything as seen so a fresh deploy does
// not storm about history; only new events report.
root.crashLinesSeen = -2;
crashLog.reload();
}
}
// Set once we have successfully read the log, so a later failure is
// distinguishable from "it has never existed".
property bool _crashLogSeen: false
property bool _crashLogFailureReported: false
FileView {
id: crashLog
path: root.stateDir + "/crashes.log"
watchChanges: true
// No crashes.log yet — nothing has ever crashed. The watcher can't
// watch a nonexistent file, so the 30s tick retries the reload, and
// each retry printed a "Read of ... failed" warning. On a healthy
// 16h session that was 1293 lines — 78% of everything in the shell
// log, drowning the file we read to verify our own changes.
//
// Absence is the *expected* state here, so it is silenced. But it is
// not silenced blind: onLoadFailed still fires, and a failure after
// we have once read the file successfully is a real fault and says
// so — once, not every 30 seconds.
printErrors: false
onFileChanged: reload()
onLoaded: {
root._crashLogSeen = true;
root._crashLogFailureReported = false;
root.consumeCrashLog();
}
onLoadFailed: {
if (root._crashLogSeen && !root._crashLogFailureReported) {
root._crashLogFailureReported = true;
console.log("[CrashReporter] crashes.log became unreadable at",
crashLog.path, "— crash reporting is blind until it returns");
}
}
}
function consumeCrashLog() {
if (root.crashLinesSeen === -1) return; // state not loaded yet
const lines = crashLog.text().split("\n").filter(l => l.trim().length > 0);
if (root.crashLinesSeen === -2) { // first-run baseline
root.crashLinesSeen = lines.length;
root.saveState();
return;
}
if (lines.length < root.crashLinesSeen) root.crashLinesSeen = 0; // rotated
if (lines.length === root.crashLinesSeen) return;
const fresh = lines.slice(root.crashLinesSeen);
root.crashLinesSeen = lines.length;
root.saveState();
// "$(date -Is) souveraine-shell result=exit-code exit=255"
const last = fresh[fresh.length - 1];
const detail = last.replace(/^\S+\s+/, "");
root.notify(
fresh.length > 1
? qsTr("Shell crashed ×%1 — recovered").arg(fresh.length)
: qsTr("Shell crashed — recovered"),
detail);
}
Timer {
interval: 30000
running: root.started
repeat: true
triggeredOnStart: true
onTriggered: {
if (crashLog.path && !crashLog.loaded) crashLog.reload();
failedUnits.running = true;
coredumps.running = true;
}
}
Process {
id: failedUnits
command: ["systemctl", "--user", "--failed", "--plain", "--no-legend"]
stdout: StdioCollector {
onStreamFinished: {
const units = text.split("\n")
.map(l => l.trim().split(/\s+/)[0])
.filter(u => u.length > 0)
// Our own unit's crashes come from crashes.log with detail;
// it also can't be in --failed while we are running.
.filter(u => u !== "souveraine-shell.service");
const fresh = units.filter(u => !root.knownFailedUnits.includes(u));
root.knownFailedUnits = units;
if (root.crashLinesSeen === -1) return; // still booting state
root.saveState();
if (fresh.length > 0) {
root.notify(
qsTr("Service failed: %1").arg(fresh.join(", ")),
qsTr("systemctl --user status for details"));
}
}
}
}
Process {
id: coredumps
command: ["sh", "-c", "coredumpctl list --no-legend 2>/dev/null | tail -1"]
stdout: StdioCollector {
onStreamFinished: {
const line = text.trim();
if (line.length === 0) return;
if (root.crashLinesSeen === -1) return;
if (line === root.lastCoredumpLine) return;
const first = root.lastCoredumpLine.length === 0;
root.lastCoredumpLine = line;
root.saveState();
if (first) return; // baseline, don't report history
// "... TIME PID UID GID SIG COREFILE EXE SIZE"
const cols = line.split(/\s+/);
const exe = cols.length >= 2 ? cols[cols.length - 2] : "?";
root.notify(qsTr("Process dumped core: %1").arg(exe), line, "normal");
}
}
}
}