extract music player deps - souveraine-player is its own crate now
This commit is contained in:
parent
dfd494c5f1
commit
8d661d2352
7 changed files with 1083 additions and 66 deletions
399
Cargo.lock
generated
399
Cargo.lock
generated
|
|
@ -613,7 +613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b"
|
||||
dependencies = [
|
||||
"atk-sys",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
|
@ -623,10 +623,10 @@ version = "0.18.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -653,6 +653,12 @@ version = "1.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "atomic_refcell"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21e4227379beff4205943696e6c3e0cd809bacdf3f0edd6e3dd153e2269571a4"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
|
|
@ -1195,7 +1201,7 @@ checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
|
|||
dependencies = [
|
||||
"bitflags 2.11.1",
|
||||
"cairo-sys-rs",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"thiserror 1.0.69",
|
||||
|
|
@ -1207,9 +1213,9 @@ version = "0.18.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1349,7 +1355,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
"target-lexicon 0.12.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.20.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb693542bcafa528e198be0ebd9d3632ca5b7c93dbe7237460e199910835997c"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon 0.13.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2533,7 +2549,7 @@ version = "0.5.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a"
|
||||
dependencies = [
|
||||
"libloading 0.7.4",
|
||||
"libloading 0.8.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3355,7 +3371,7 @@ dependencies = [
|
|||
"gdk-pixbuf",
|
||||
"gdk-sys",
|
||||
"gio",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
"pango",
|
||||
]
|
||||
|
|
@ -3368,7 +3384,7 @@ checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec"
|
|||
dependencies = [
|
||||
"gdk-pixbuf-sys",
|
||||
"gio",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
|
@ -3379,11 +3395,11 @@ version = "0.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
|
||||
dependencies = [
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gio-sys 0.18.1",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3394,13 +3410,13 @@ checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7"
|
|||
dependencies = [
|
||||
"cairo-sys-rs",
|
||||
"gdk-pixbuf-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gio-sys 0.18.1",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"pkg-config",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3410,11 +3426,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69"
|
||||
dependencies = [
|
||||
"gdk-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3426,7 +3442,7 @@ dependencies = [
|
|||
"gdk",
|
||||
"gdkx11-sys",
|
||||
"gio",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
"x11",
|
||||
]
|
||||
|
|
@ -3438,9 +3454,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d"
|
||||
dependencies = [
|
||||
"gdk-sys",
|
||||
"glib-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
"x11",
|
||||
]
|
||||
|
||||
|
|
@ -3580,8 +3596,8 @@ dependencies = [
|
|||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"gio-sys 0.18.1",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
|
|
@ -3595,13 +3611,26 @@ version = "0.18.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gio-sys"
|
||||
version = "0.22.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "353fdc7da7cd16da916104b1e0e4e7de380ec9c8aaa20d4d742d66310ab4b0d5"
|
||||
dependencies = [
|
||||
"glib-sys 0.22.8",
|
||||
"gobject-sys 0.22.6",
|
||||
"libc",
|
||||
"system-deps 7.0.8",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.19.0"
|
||||
|
|
@ -3638,10 +3667,10 @@ dependencies = [
|
|||
"futures-executor",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"gio-sys",
|
||||
"glib-macros",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gio-sys 0.18.1",
|
||||
"glib-macros 0.18.5",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
|
|
@ -3649,6 +3678,27 @@ dependencies = [
|
|||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.22.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddbcf514bd1881fc1b960e4e52b4e82873f4da3bceddbd58d42827b508888100"
|
||||
dependencies = [
|
||||
"bitflags 2.11.1",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
"gio-sys 0.22.8",
|
||||
"glib-macros 0.22.6",
|
||||
"glib-sys 0.22.8",
|
||||
"gobject-sys 0.22.6",
|
||||
"libc",
|
||||
"memchr",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-macros"
|
||||
version = "0.18.5"
|
||||
|
|
@ -3663,6 +3713,18 @@ dependencies = [
|
|||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-macros"
|
||||
version = "0.22.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "506d23499707c7142898429757e8d9a3871d965239a2cb66dfa05052be6d6f19"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.18.1"
|
||||
|
|
@ -3670,7 +3732,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glib-sys"
|
||||
version = "0.22.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "030967459f9f676851872c6304adea7825c6d462ec9b72554c733cf0c5952233"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"system-deps 7.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3718,9 +3790,20 @@ version = "0.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.22.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a861859b887a79cf461359c192c97a57d8fb0229dd291232e57aa11f6fa72c"
|
||||
dependencies = [
|
||||
"glib-sys 0.22.8",
|
||||
"libc",
|
||||
"system-deps 7.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3751,7 +3834,7 @@ dependencies = [
|
|||
"log",
|
||||
"presser",
|
||||
"thiserror 1.0.69",
|
||||
"windows 0.54.0",
|
||||
"windows 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3786,6 +3869,99 @@ dependencies = [
|
|||
"xxhash-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gstreamer"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab4527e1b9bae8d29ce137bde5b8eec8ae8f78f13ad00fc6e70cbe227d6ad027"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"glib 0.22.8",
|
||||
"gstreamer-sys",
|
||||
"itertools 0.15.0",
|
||||
"kstring",
|
||||
"libc",
|
||||
"muldiv",
|
||||
"num-integer",
|
||||
"num-rational",
|
||||
"option-operations",
|
||||
"pastey 0.2.2",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gstreamer-app"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97f8ae9238c2352398dcc084de28df3f7099af216ac6c160b52318d23f25c010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"glib 0.22.8",
|
||||
"gstreamer",
|
||||
"gstreamer-app-sys",
|
||||
"gstreamer-base",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gstreamer-app-sys"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a74a8211e5d7df2f45b612c284ddf56b92bdf4e879e8ed72e7c46dd0842e158"
|
||||
dependencies = [
|
||||
"glib-sys 0.22.8",
|
||||
"gstreamer-base-sys",
|
||||
"gstreamer-sys",
|
||||
"libc",
|
||||
"system-deps 7.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gstreamer-base"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c91c94a4d3047d05dd6e1f6d91c74f61f56384c7ea1c9d0c1051572eeeb0138d"
|
||||
dependencies = [
|
||||
"atomic_refcell",
|
||||
"cfg-if",
|
||||
"glib 0.22.8",
|
||||
"gstreamer",
|
||||
"gstreamer-base-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gstreamer-base-sys"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "709fbbc623dc066908ba10c43d629c21096508dea04796592a206c4edd864e37"
|
||||
dependencies = [
|
||||
"glib-sys 0.22.8",
|
||||
"gobject-sys 0.22.6",
|
||||
"gstreamer-sys",
|
||||
"libc",
|
||||
"system-deps 7.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gstreamer-sys"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "533fa8d28fc830eafccbcfcfddb390563ea5d3a351af2c3aab99e197e5f5b1ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"glib-sys 0.22.8",
|
||||
"gobject-sys 0.22.6",
|
||||
"libc",
|
||||
"system-deps 7.0.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gtk"
|
||||
version = "0.18.2"
|
||||
|
|
@ -3799,7 +3975,7 @@ dependencies = [
|
|||
"gdk",
|
||||
"gdk-pixbuf",
|
||||
"gio",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"gtk-sys",
|
||||
"gtk3-macros",
|
||||
"libc",
|
||||
|
|
@ -3817,12 +3993,12 @@ dependencies = [
|
|||
"cairo-sys-rs",
|
||||
"gdk-pixbuf-sys",
|
||||
"gdk-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gio-sys 0.18.1",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"pango-sys",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4580,6 +4756,15 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.18"
|
||||
|
|
@ -4593,7 +4778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"javascriptcore-rs-sys",
|
||||
]
|
||||
|
||||
|
|
@ -4603,10 +4788,10 @@ version = "1.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4849,6 +5034,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kstring"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b609e7ca5ea38f093c20a4a102335b247221c9643b7a6bc3510f196f99499a9e"
|
||||
dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lab"
|
||||
version = "0.11.0"
|
||||
|
|
@ -4900,7 +5094,7 @@ version = "0.9.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a"
|
||||
dependencies = [
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"gtk",
|
||||
"gtk-sys",
|
||||
"libappindicator-sys",
|
||||
|
|
@ -5108,6 +5302,32 @@ dependencies = [
|
|||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lofty"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec4feeff6c7d75093278133a06e827d7af6d2bfe20b0f331f9d10338a5ec7ca"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"data-encoding",
|
||||
"flate2",
|
||||
"lofty_attr",
|
||||
"log",
|
||||
"ogg_pager",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lofty_attr"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458ace39169e4b83c4f77ae3d42d5d1d11c422feef590219a97c973d3b524557"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.29"
|
||||
|
|
@ -5565,6 +5785,12 @@ dependencies = [
|
|||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "muldiv"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "956787520e75e9bd233246045d19f42fb73242759cc57fba9611d940ae96d4b0"
|
||||
|
||||
[[package]]
|
||||
name = "murmurhash32"
|
||||
version = "0.3.1"
|
||||
|
|
@ -6371,6 +6597,15 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ogg_pager"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d36b1d6964c3ac92b7aea701057e02b6b91143d70d83b20abf75a231a3c0216"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.4"
|
||||
|
|
@ -6466,6 +6701,15 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "option-operations"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aca39cf52b03268400c16eeb9b56382ea3c3353409309b63f5c8f0b1faf42754"
|
||||
dependencies = [
|
||||
"pastey 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.55"
|
||||
|
|
@ -6590,7 +6834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
|
||||
dependencies = [
|
||||
"gio",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"pango-sys",
|
||||
|
|
@ -6602,10 +6846,10 @@ version = "0.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
|
||||
dependencies = [
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -9040,7 +9284,7 @@ checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f"
|
|||
dependencies = [
|
||||
"futures-channel",
|
||||
"gio",
|
||||
"glib",
|
||||
"glib 0.18.5",
|
||||
"libc",
|
||||
"soup3-sys",
|
||||
]
|
||||
|
|
@ -9051,11 +9295,11 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27"
|
||||
dependencies = [
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gio-sys 0.18.1",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"libc",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -9087,7 +9331,10 @@ dependencies = [
|
|||
"figlet-rs",
|
||||
"futures",
|
||||
"git2",
|
||||
"glib 0.22.8",
|
||||
"glob",
|
||||
"gstreamer",
|
||||
"gstreamer-app",
|
||||
"hex",
|
||||
"hkdf",
|
||||
"hound",
|
||||
|
|
@ -9095,6 +9342,7 @@ dependencies = [
|
|||
"keyring",
|
||||
"keyring-core",
|
||||
"libc",
|
||||
"lofty",
|
||||
"matrix-sdk",
|
||||
"notify",
|
||||
"num-bigint",
|
||||
|
|
@ -9670,13 +9918,26 @@ version = "6.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
|
||||
dependencies = [
|
||||
"cfg-expr",
|
||||
"cfg-expr 0.15.8",
|
||||
"heck 0.5.0",
|
||||
"pkg-config",
|
||||
"toml 0.8.2",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "7.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396a35feb67335377e0251fcbc1092fc85c484bd4e3a7a54319399da127796e7"
|
||||
dependencies = [
|
||||
"cfg-expr 0.20.8",
|
||||
"heck 0.5.0",
|
||||
"pkg-config",
|
||||
"toml 1.1.2+spec-1.1.0",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tantivy"
|
||||
version = "0.26.1"
|
||||
|
|
@ -9888,6 +10149,12 @@ version = "0.12.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.11.1"
|
||||
|
|
@ -11876,10 +12143,10 @@ dependencies = [
|
|||
"gdk",
|
||||
"gdk-sys",
|
||||
"gio",
|
||||
"gio-sys",
|
||||
"glib",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gio-sys 0.18.1",
|
||||
"glib 0.18.5",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"gtk",
|
||||
"gtk-sys",
|
||||
"javascriptcore-rs",
|
||||
|
|
@ -11898,15 +12165,15 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
"cairo-sys-rs",
|
||||
"gdk-sys",
|
||||
"gio-sys",
|
||||
"glib-sys",
|
||||
"gobject-sys",
|
||||
"gio-sys 0.18.1",
|
||||
"glib-sys 0.18.1",
|
||||
"gobject-sys 0.18.0",
|
||||
"gtk-sys",
|
||||
"javascriptcore-rs-sys",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"soup3-sys",
|
||||
"system-deps",
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ git2 = { version = "0.19", default-features = false }
|
|||
# Database (server mode)
|
||||
sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite", "migrate", "chrono", "json"] }
|
||||
|
||||
|
||||
# Concurrent collections (server sessions)
|
||||
dashmap = "5"
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,8 @@
|
|||
| `souveraine-subconscious-naming.md` | 2 | pending | Clarify naming: Ani's subconscious = Aster, Souveraine agents' subconscious = Souveraine-subconscious. |
|
||||
| `quickshell-surface-package.md` | delivery | **in progress** | Split core from QuickShell surface package; safe preview/adopt installer, no automatic ii overwrite. |
|
||||
| `device-specific-quickshell-profiles.md` | delivery | scoped | Phone and laptop share the agent channel but have distinct QuickShell bodies, manifests, and packages. |
|
||||
| `souveraine-settings-ipc-profiles.md` | design | scoped | One typed, audited settings authority for UI + agent IPC, exact-diff step-up proposals, and atomic named profiles. |
|
||||
| `souveraine-native-audio-privacy.md` | delivery | **in progress** | Original AGPL PulseAudio controls and truthful privacy surfaces; PipeWire retained only for portal video. |
|
||||
| `power-indication.md` | delivery | scoped | Charging state, honest full detection (state not onBattery — kills "Charging 1% forever"), a PowerService singleton, and charge-aware idle policy (sleep-inhibit while charging, wake-on-charge). |
|
||||
| `footer-cleanup.md` | 3.0 | **landed** | Removed S-Ret indicator, scroll hint, posture label. Footer: Esc menu · Tab · tool hint · conv ID · ctx%. |
|
||||
| `ui-styling-cleanup.md` | 3.0 | pending | UI styling polish for cockpit/subconscious/thinking boxes — sentences run together, needs formatting and visual cleanup. |
|
||||
|
|
|
|||
46
docs/tasks/souveraine-lock-primitives-session-prompt.md
Normal file
46
docs/tasks/souveraine-lock-primitives-session-prompt.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Next session — Souveraine-owned AGPL lock primitives
|
||||
|
||||
> Paste this into the next session as the opening message. It is orders, not
|
||||
> a draft. Related task doc: `docs/tasks/souveraine-lock-primitives.md`.
|
||||
|
||||
---
|
||||
|
||||
We're building the Souveraine-owned lock surface. Read
|
||||
`docs/tasks/souveraine-lock-primitives.md` first — it's the full spec:
|
||||
dependency set, the primitive tiers, the build order, done-when criteria.
|
||||
|
||||
## Non-negotiables (do not re-litigate)
|
||||
|
||||
1. **SouveraineOS, not ii OS.** Cut the cord from ii by **rewriting**, never
|
||||
vendoring. ii files inherit GPLv3; we will not ship ii-derived files.
|
||||
Every primitive is original Souveraine AGPL, Casey as copyright holder.
|
||||
2. **Build the end goal, not v1/v2.** No borrowed-widget bridges. The lock
|
||||
may not compile or may miss a subcomponent while the owned primitives
|
||||
are built — that's preferable to a single compromise. Full AGPL lock
|
||||
dep graph is the target.
|
||||
3. **ii is behavioral reference only.** Read how ii's widget behaves (on the
|
||||
phone at `~/.config/quickshell/ii/modules/common/widgets/`, `ssh pixel`);
|
||||
do not copy. Write fresh.
|
||||
4. **No subagents for this.** Write the code in the main conversation.
|
||||
5. **No mid-session paperwork** beyond the task doc that already exists.
|
||||
Don't write PLAN.md / handoffs / memory unless asked.
|
||||
6. **Don't run build/test loops as the model if you're Opus.** Verify once
|
||||
with the real build.
|
||||
|
||||
## Start here
|
||||
|
||||
Tier 0 (`Appearance` / `ColorUtils` / `Translation`) — nothing compiles
|
||||
without them, and `Appearance` is where the Souveraine lock palette gets
|
||||
defined (retire the scattered `#d9ffffff` etc. literals). Confirm the
|
||||
target path (`modules/souveraine/widgets/` unless Casey says otherwise),
|
||||
then Tier 0 → Tier 1 (`StyledText`, `MaterialSymbol`, `MaterialShape`,
|
||||
`ErrorShakeAnimation`) → Tier 2 (`RippleButton`) → Tier 3 (`AmbientCard`,
|
||||
`PinDots`, `LockKeypad`, `LockUtilityRow`, `LockReveal`) → rewire
|
||||
`TouchLockSurface.qml` + the two cards → manifest lines → deploy.
|
||||
|
||||
Behavior reference on the phone: ii widgets at
|
||||
`~/.config/quickshell/ii/modules/common/widgets/`; Phosh lockscreen at
|
||||
`~/build/phosh/src/lockscreen.c` + `ui/lockscreen.ui` (swipe-capture model,
|
||||
shake midpoint-crossing termination — implement in QML, do not port).
|
||||
|
||||
Go.
|
||||
191
docs/tasks/souveraine-lock-primitives.md
Normal file
191
docs/tasks/souveraine-lock-primitives.md
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
task_id: souveraine-lock-primitives-001
|
||||
title: "Souveraine-owned AGPL lock primitives — cut the cord from ii by rewriting"
|
||||
status: pending
|
||||
priority: high
|
||||
phase: build
|
||||
created: 2026-07-18
|
||||
references: docs/tasks/qs-souveraine-composer.md, docs/DECISIONS.md, ~/Projects/MAKE_PROPER_LICENSES_FOR_ALL_PROJECTS.md, surfaces/quickshell/modules/ii/lock/TouchLockSurface.qml, surfaces/quickshell/modules/souveraine/lock/
|
||||
---
|
||||
|
||||
# Souveraine-owned AGPL lock primitives
|
||||
|
||||
## The end goal (build THIS, not an increment)
|
||||
|
||||
A fully Souveraine-owned, fully AGPL lock surface. Zero ii-derived files in
|
||||
the lock dependency graph. Every primitive the lock uses is original
|
||||
Souveraine-authored QML, licensed AGPLv3, designed to behave how *we* want
|
||||
— not a copy of ii.
|
||||
|
||||
There is no v1/v2 here. We do not vendor ii files. We do not borrow ii
|
||||
widgets as a bridge. We accept that the lock may not compile, or may be
|
||||
missing a subcomponent, while the owned primitives are built. That is
|
||||
preferable to a single borrowed-widget compromise. See the cord-cut rule in
|
||||
`docs/DECISIONS.md` ("Shell = own config") and
|
||||
`docs/tasks/qs-souveraine-composer.md`.
|
||||
|
||||
## Why rewrite, not vendor
|
||||
|
||||
Vendoring an ii file inherits GPLv3 — we can never make it ours by
|
||||
relabeling. The licensing master doc governs the boundary: original
|
||||
Souveraine files get AGPL headers + Casey as copyright holder; genuinely
|
||||
inherited GPLv3 files keep their headers. Because we choose to author
|
||||
rather than inherit, every lock primitive will be original AGPL, and the
|
||||
lock surface conveys cleanly under our license. ii is behavioral reference
|
||||
only — read how it behaves, write our own implementation. Do not copy.
|
||||
|
||||
## What the lock surface currently depends on
|
||||
|
||||
Direct external symbols referenced by the lock files (verified by grep,
|
||||
2026-07-18):
|
||||
|
||||
| Symbol | Used by | What it is |
|
||||
|--------|---------|------------|
|
||||
| `RippleButton` | `TouchLockSurface.qml` (KeypadButton, UtilityButton inline components) | Pressable button with material-ripple feedback. Transitive ii dep: `MaterialShape`. |
|
||||
| `StyledText` | `TouchLockSurface.qml` (dots hint, keypad glyphs, hint labels) | Themed text bound to `Appearance` colors/fonts. |
|
||||
| `MaterialSymbol` | `TouchLockSurface.qml` (icons: backspace, arrow, power, reboot) | Material Symbols icon glyph. |
|
||||
| `ErrorShakeAnimation` | `TouchLockSurface.qml` (wrong-PIN shake on `dotsArea`) | Frame-driven horizontal shake animation. |
|
||||
| `Appearance` (singleton) | `TouchLockSurface.qml` (15×), `LockScreen.qml` (1×). The host + cards use raw literals instead — evidence for the palette work below. | Colors (`colOnLayer1`, `colError`, `colSubtext`, `colOnSurfaceVariant`, `colOnPrimary`) + font pixel sizes. |
|
||||
| `ColorUtils` | `TouchLockSurface.qml` | `transparentize()`. |
|
||||
| `Translation` | `TouchLockSurface.qml` | `tr()` i18n. |
|
||||
| `MaterialShape` | transitive (used by ii's RippleButton) | Material-style rounded/shape background. First-class rewrite target since our RippleButton needs it. |
|
||||
|
||||
Everything else in the lock files is QtQuick/QtQuick.Layouts/Quickshell
|
||||
(primitives we keep) or Souveraine-owned already (`GlobalStates`,
|
||||
`LockContext`, `Config`, `LockContentPolicy`, `Ai`, `Battery`,
|
||||
`LockSurfaceHost`, `LockMediaCard`, `LockAgentCard`).
|
||||
|
||||
## What to build (the primitive set)
|
||||
|
||||
All under a Souveraine-owned path — propose
|
||||
`surfaces/quickshell/modules/souveraine/widgets/` — each file original AGPL,
|
||||
Casey as copyright holder, designed from the lock's needs with ii as
|
||||
behavioral reference only.
|
||||
|
||||
### Tier 0 — theme singletons (these are not optional; everything below keys off them)
|
||||
|
||||
- **`Appearance`** — colors + font scale. This is the single source of truth
|
||||
every styled component reads. Decide the Souveraine lock palette here
|
||||
(replacing the scattered literals `#d9ffffff`, `#e6ffffff`, `#1c1b20`,
|
||||
`#b3181b20`, `#22000000`, `#33ffffff`, `#55ffffff` currently hand-rolled
|
||||
across the three lock cards). One palette, named tokens.
|
||||
- **`ColorUtils`** — at minimum `transparentize(color, amount)`.
|
||||
- **`Translation`** — `tr()` passthrough to whatever i18n we standardize on.
|
||||
|
||||
### Tier 1 — visual primitives
|
||||
|
||||
- **`StyledText`** — text bound to Appearance tokens; the type every label
|
||||
uses.
|
||||
- **`MaterialSymbol`** — icon glyph renderer.
|
||||
- **`MaterialShape`** — material background shape (rounded rect minimum;
|
||||
designed so `RippleButton` can compose it).
|
||||
- **`ErrorShakeAnimation`** — horizontal shake with the *midpoint-crossing
|
||||
termination* rule (stop when the oscillation would cross the rest point,
|
||||
not on a fixed timer — Phosh's `shake_entry` model, frame-clock driven).
|
||||
|
||||
### Tier 2 — composite primitives (compose Tier 1)
|
||||
|
||||
- **`RippleButton`** — the pressable button. Ripple feedback baked in from
|
||||
day one (this is one of the "minor details" Casey wants to tweak — build
|
||||
it ours, tunable). Properties the lock uses today: `contentItem`,
|
||||
`colBackground`, `buttonRadius`, `toggled`, `enabled`, signals
|
||||
`clicked`/`pressAndHold`.
|
||||
|
||||
### Tier 3 — lock-surface components (built on the owned primitives)
|
||||
|
||||
These replace the inline blocks in `TouchLockSurface.qml`:
|
||||
|
||||
- **`AmbientCard`** — the shared bordered rounded-rect card both
|
||||
`LockMediaCard` and `LockAgentCard` currently hand-roll with different
|
||||
radii/alphas. One primitive, one palette.
|
||||
- **`PinDots`** — the entered-PIN dots row + empty-state hint, with
|
||||
`ErrorShakeAnimation` wired in.
|
||||
- **`LockKeypad`** — the 3×3 + 0/backspace/confirm grid, built from our
|
||||
`RippleButton`.
|
||||
- **`LockUtilityRow`** — power / battery / reboot, from our `RippleButton`.
|
||||
- **`LockReveal`** — the glance↔PIN stage controller. Owns the reveal
|
||||
intent (`reveal()`, `retreat()`) so every input path (swipe, tap-hint,
|
||||
hardware key, future double-tap-clock) funnels through one transition
|
||||
instead of each re-implementing threshold logic. Replaces the inline
|
||||
`pressY`/threshold/retreat-timer block in `TouchLockSurface.qml`.
|
||||
|
||||
### The result
|
||||
|
||||
`TouchLockSurface.qml` shrinks to ~layout + intent wiring (target ~60–80
|
||||
lines), built entirely on Souveraine-owned AGPL QML. The lock dep graph has
|
||||
zero ii-derived files.
|
||||
|
||||
## How to build it (approach, not steps)
|
||||
|
||||
1. **Tier 0 first.** `Appearance`/`ColorUtils`/`Translation` — nothing else
|
||||
compiles without them. Define the Souveraine lock palette here as named
|
||||
tokens; retire the scattered literals.
|
||||
2. **Tier 1 next**, in dependency order: `StyledText` (needs Appearance),
|
||||
`MaterialSymbol`, `MaterialShape`, then `ErrorShakeAnimation`
|
||||
(standalone).
|
||||
3. **Tier 2:** `RippleButton` (composes `MaterialShape`).
|
||||
4. **Tier 3:** `AmbientCard`, `PinDots`, `LockKeypad`, `LockUtilityRow`,
|
||||
`LockReveal` — built on Tiers 0–2.
|
||||
5. **Rewire `TouchLockSurface`** and the two cards to consume the owned
|
||||
primitives, removing every ii import.
|
||||
|
||||
Each file lands with an AGPLv3 header and Casey as copyright holder.
|
||||
Behavioral reference from ii is fine (read how ii's `RippleButton` feels,
|
||||
what properties it exposes); copying is not.
|
||||
|
||||
## ii reference access (behavioral, read-only)
|
||||
|
||||
ii's widget sources are NOT in this repo. They live on the phone at
|
||||
`/home/casey/.config/quickshell/ii/modules/common/widgets/` (RippleButton,
|
||||
StyledText, MaterialSymbol, MaterialShape, ErrorShakeAnimation, etc.) and
|
||||
on the laptop at `~/.config/quickshell/ii/`. SSH: `ssh pixel`. Read them to
|
||||
understand behavior and the property contract the lock code expects — do
|
||||
not copy. Write fresh AGPL implementations.
|
||||
|
||||
Phosh's lockscreen source is also on the phone at `~/build/phosh/src/`
|
||||
(`lockscreen.c`, `ui/lockscreen.ui`) — useful behavioral reference for the
|
||||
swipe-capture model (deck/carousel, rounded-progress page gating) and the
|
||||
shake midpoint-crossing termination. Do not port; implement in QML.
|
||||
|
||||
## Manifest + composer wiring
|
||||
|
||||
Every new Souveraine-owned file needs a line in
|
||||
`surfaces/quickshell/deploy.sh` `MANIFEST` (the composer only ships files
|
||||
in the manifest — a missing line means "is not a type" at load). As files
|
||||
are written, add manifest lines pointing them into the `souveraine/`
|
||||
composed config. Borrowed ii widget dirs stay borrowed for the rest of the
|
||||
shell until their own cord-cut; only the lock's deps are cut here.
|
||||
|
||||
## License headers
|
||||
|
||||
Per `~/Projects/MAKE_PROPER_LICENSES_FOR_ALL_PROJECTS.md`:
|
||||
|
||||
- Every file written here: AGPLv3 header, Casey Tunturi as copyright holder.
|
||||
- Do NOT put inherited GPLv3 headers on these — they are original work.
|
||||
- Mixed tree is honest: the lock dep graph is all-original AGPL after this
|
||||
task; other parts of the shell may still carry inherited GPLv3 until their
|
||||
own rewrite.
|
||||
|
||||
## Non-goals / out of scope for this task
|
||||
|
||||
- Rewriting non-lock widgets (dock, sidebar, overview, etc.) — separate
|
||||
cord-cuts, separate tasks.
|
||||
- Changing lock *behavior* beyond what the primitive rewrite naturally
|
||||
enables. Feature additions (clock double-tap, new gesture paths, peek
|
||||
mode) are follow-on work on top of the owned primitives, not part of
|
||||
getting the substrate owned.
|
||||
- Touching sessiond (Rust) — it is already Souveraine-owned and unaffected.
|
||||
|
||||
## Done when
|
||||
|
||||
- [ ] Tier 0–2 primitives exist as original AGPL files under
|
||||
`modules/souveraine/widgets/` (or agreed path), each with AGPL header.
|
||||
- [ ] Tier 3 lock components exist, built on the owned primitives.
|
||||
- [ ] `TouchLockSurface.qml` + both lock cards import only Souveraine-owned
|
||||
+ Qt/Quickshell modules — zero `qs.modules.common.widgets`
|
||||
ii-borrowed imports in the lock graph.
|
||||
- [ ] The lock surface dep graph contains no ii-derived files (grep
|
||||
verifiable).
|
||||
- [ ] Manifest lines added; `deploy.sh --phone` ships and the lock runs.
|
||||
- [ ] Cord-cut ledger updated (this file's "Done when", or a dedicated
|
||||
ledger) recording which borrowed dirs remain.
|
||||
252
docs/tasks/souveraine-native-audio-privacy.md
Normal file
252
docs/tasks/souveraine-native-audio-privacy.md
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
---
|
||||
task_id: souveraine-native-audio-001
|
||||
title: "Souveraine native audio and privacy surfaces — PulseAudio for sound, PipeWire for portals"
|
||||
status: in_progress
|
||||
priority: high
|
||||
phase: delivery
|
||||
created: 2026-07-18
|
||||
references:
|
||||
- surfaces/quickshell/services/Audio.qml
|
||||
- surfaces/quickshell/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml
|
||||
- surfaces/quickshell/modules/ii/bar/UtilButtons.qml
|
||||
- surfaces/quickshell/deploy.sh
|
||||
- /home/casey/Projects/Pixel3Arch/rootfs-overlay/etc/pulse/default.pa.d/90-blueline-alsa.pa
|
||||
- /home/casey/Projects/Pixel3Arch/pkgs/pipewire-abi-provider/PKGBUILD
|
||||
- docs/tasks/souveraine-settings-ipc-profiles.md
|
||||
- docs/tasks/souveraine-lock-primitives.md
|
||||
---
|
||||
|
||||
# Souveraine native audio and privacy surfaces
|
||||
|
||||
## End goal
|
||||
|
||||
Souveraine owns the complete audio control and privacy presentation for phone
|
||||
and laptop. Native PulseAudio is the only audio server. PipeWire exists only as
|
||||
the video transport required by screen-cast/camera portals; `pipewire-pulse` is
|
||||
never started and never owns an audio device.
|
||||
|
||||
The user and agents see one truthful audio model:
|
||||
|
||||
- the real default output and input;
|
||||
- output/input volume and mute;
|
||||
- which applications hold playback or recording streams;
|
||||
- a visible, persistent microphone/camera/screen-capture privacy indicator;
|
||||
- device switching where more than one real endpoint exists;
|
||||
- structured IPC methods guarded by the settings/capability authority;
|
||||
- no ii or PipeWire audio assumptions in the active dependency graph.
|
||||
|
||||
This is an original AGPL Souveraine implementation. The current files under
|
||||
`modules/ii/` are functional scaffolding and behavioral evidence, not the
|
||||
destination and not files to relabel.
|
||||
|
||||
## Ground truth as of 2026-07-18
|
||||
|
||||
The important PulseAudio foundation is already present:
|
||||
|
||||
- `services/Audio.qml` is PulseAudio-backed and mirrors both the default sink
|
||||
and the default source through `pactl`.
|
||||
- It has real source volume/mute setters, `toggleMicMute()`, `sourceReady`,
|
||||
`inputDevices`, and a first `micActive` signal based on Pulse source outputs.
|
||||
- `VolumeDialogContent.qml` presents a real input page and binds the slider to
|
||||
`Audio.source` rather than a fake microphone object.
|
||||
- `UtilButtons.qml` now calls `Audio.toggleMicMute()` and reads the real source
|
||||
mute state.
|
||||
- Pixel3Arch autoloads the handset capture PCM as the named Pulse source
|
||||
`blueline_mic`, makes it the default source, and uses UCM to establish the
|
||||
handset route before PulseAudio starts.
|
||||
|
||||
Do not reopen those solved questions or restore PipeWire audio. The remaining
|
||||
work is ownership, completeness, event accuracy, privacy presentation, IPC,
|
||||
and portal coexistence.
|
||||
|
||||
## The architectural boundary
|
||||
|
||||
| Function | Authority |
|
||||
|---|---|
|
||||
| Speaker/headphone playback | native PulseAudio |
|
||||
| Handset/external microphone capture | native PulseAudio |
|
||||
| Per-app audio streams | native PulseAudio sink-input/source-output model |
|
||||
| Audio device selection | native PulseAudio defaults and profiles |
|
||||
| Screen-cast frames | PipeWire portal transport |
|
||||
| Camera frames | PipeWire portal transport where the portal requires it |
|
||||
| Audio for screen recording | explicit PulseAudio capture chosen by the recorder; never `pipewire-pulse` |
|
||||
|
||||
PipeWire's presence must not imply it is an audio server. Packaging and user
|
||||
units enforce the boundary: no Pulse compatibility daemon, no ALSA device
|
||||
acquisition by PipeWire, and no competing session policy for sound.
|
||||
|
||||
## Owned service model
|
||||
|
||||
Replace the scaffolding with an original `SouveraineAudio.qml` service (final
|
||||
name may remain `Audio` for call-site stability). It projects:
|
||||
|
||||
```text
|
||||
serverReady
|
||||
defaultSink / defaultSource
|
||||
sinks[] / sources[]
|
||||
playbackStreams[] / recordingStreams[]
|
||||
outputActive / microphoneActive
|
||||
lastError / generation
|
||||
```
|
||||
|
||||
Each device and stream has a stable, typed shape: Pulse name/index,
|
||||
description, availability, volume, mute, monitor/physical classification,
|
||||
application identity, media role, corked/running state, and owning PID when
|
||||
Pulse exposes it. Do not infer a microphone from `hw:0,1` naming alone;
|
||||
`blueline_mic` is the board's canonical source name, while laptops may publish
|
||||
different source names.
|
||||
|
||||
### Event model
|
||||
|
||||
The current 1.5-second `pactl` snapshot is acceptable diagnostic scaffolding
|
||||
but not the final privacy mechanism. The owned service keeps one long-lived
|
||||
`pactl subscribe` observer, debounces server events, then refreshes a complete
|
||||
machine-readable snapshot. Prefer `pactl --format=json` when supported and a
|
||||
small owned parser/fallback when it is not; do not parse localized display
|
||||
labels.
|
||||
|
||||
Loss/restart of PulseAudio increments `generation`, clears stale objects, and
|
||||
repopulates defaults. Sink readiness and source readiness remain independent:
|
||||
a missing microphone must never disable speaker controls.
|
||||
|
||||
Every setter returns a structured result or emits an error with the affected
|
||||
object. The UI does not optimistically lie when `pactl` fails.
|
||||
|
||||
## Privacy truth
|
||||
|
||||
Build one owned `PrivacyService` that consumes actual subsystem activity, not
|
||||
UI toggles:
|
||||
|
||||
- `microphoneActive`: at least one Pulse source-output exists; expose the
|
||||
application identities and whether streams are corked.
|
||||
- `cameraActive`: portal/camera session ownership, not merely device presence.
|
||||
- `screenCaptureActive`: active portal screencast or Souveraine recorder
|
||||
session.
|
||||
|
||||
The prior borrowed Privacy model must not be reused: converting an array with
|
||||
`.map(...)` to a boolean is always truthy and is not evidence of access. The
|
||||
owned implementation uses explicit collection predicates and retains the
|
||||
participants needed for disclosure.
|
||||
|
||||
Privacy indication is not configurable away. Appearance may vary, but active
|
||||
capture always has a persistent visible indicator on the unlocked shell and a
|
||||
safe ambient indication on the lock surface. Opening it shows which
|
||||
application is accessing what and offers a stop/revoke action where the
|
||||
underlying subsystem supports one. Unknown clients are displayed as unknown,
|
||||
not hidden.
|
||||
|
||||
Muting the microphone and stopping access are distinct operations:
|
||||
|
||||
- mute changes the default source's audio value;
|
||||
- stop/revoke terminates or denies a recording stream/session;
|
||||
- the indicator remains visible while a client still holds the stream, even if
|
||||
the source is muted.
|
||||
|
||||
This distinction prevents a muted-but-still-recording process from becoming
|
||||
invisible.
|
||||
|
||||
## Owned surfaces
|
||||
|
||||
Create original Souveraine AGPL components under Souveraine paths:
|
||||
|
||||
- `services/SouveraineAudio.qml` — authoritative Pulse model and methods.
|
||||
- `services/PrivacyService.qml` — cross-subsystem access truth.
|
||||
- `modules/souveraine/audio/VolumeSurface.qml` — output/input tabs, real
|
||||
endpoint state, and per-app streams.
|
||||
- `modules/souveraine/audio/DeviceRow.qml` and `StreamRow.qml` — reusable owned
|
||||
presentation primitives.
|
||||
- `modules/souveraine/privacy/PrivacyIndicator.qml` — persistent compact state.
|
||||
- `modules/souveraine/privacy/PrivacyDetails.qml` — identities and stop/revoke
|
||||
actions.
|
||||
- phone and laptop hosts that place the same semantic components according to
|
||||
their own form-factor contract.
|
||||
|
||||
Rewire active bars/sidebars to these components, then remove the corresponding
|
||||
`modules/ii` overrides and borrowed imports from the active graph. Do not copy
|
||||
or vendor ii widgets while doing so; use the Souveraine-owned primitive layer.
|
||||
|
||||
## IPC and agent reach
|
||||
|
||||
Expose a JSON-over-string `audio` IPC surface because Quickshell drops `var`
|
||||
returns:
|
||||
|
||||
```text
|
||||
audio.state()
|
||||
audio.devices(direction)
|
||||
audio.streams(direction)
|
||||
audio.setVolume(direction, value, reason)
|
||||
audio.setMuted(direction, muted, reason)
|
||||
audio.setDefault(direction, pulseName, reason)
|
||||
audio.stopStream(streamId, reason)
|
||||
```
|
||||
|
||||
Read-only state is ambient. Ordinary volume/mute changes are direct low-risk
|
||||
settings/actions and audited. Changing a default endpoint is direct while
|
||||
unlocked unless the settings schema says otherwise. Stopping another
|
||||
application's recording stream is a physical/privacy action: an agent may
|
||||
propose it, and human surfaces may act according to the settings authority's
|
||||
policy. IPC never invents a second authorization model.
|
||||
|
||||
All methods validate direction, ranges, endpoint existence, Pulse generation,
|
||||
and current lock/security state. They return `{ok:false, reason}` rather than
|
||||
silently no-oping.
|
||||
|
||||
## Portal-only PipeWire
|
||||
|
||||
The current Pixel3Arch `pipewire-abi-provider` conflicts with the PipeWire
|
||||
daemon and WirePlumber. That satisfies ABI consumers but makes real portal
|
||||
screen sharing impossible. Split the packaging policy:
|
||||
|
||||
1. retain native PulseAudio and its ALSA ownership;
|
||||
2. install a real PipeWire daemon plus the minimal session/portal policy needed
|
||||
for video nodes;
|
||||
3. explicitly mask/omit `pipewire-pulse`;
|
||||
4. prevent WirePlumber/PipeWire from claiming ALSA audio devices, or use a
|
||||
portal-video-only configuration if the selected session manager supports
|
||||
it;
|
||||
5. verify `xdg-desktop-portal` and the compositor portal can establish a
|
||||
screencast without changing Pulse sinks/sources.
|
||||
|
||||
This packaging repair belongs in Pixel3Arch and must be tested as a system
|
||||
contract. Souveraine surfaces consume its portal state; they do not launch an
|
||||
ad-hoc competing PipeWire audio stack.
|
||||
|
||||
## Verification matrix
|
||||
|
||||
Verify on both phone and laptop:
|
||||
|
||||
1. Pulse starts with the intended default sink/source and no `pipewire-pulse`
|
||||
socket or daemon.
|
||||
2. Source/sink volume and mute changes round-trip through Pulse and survive a
|
||||
service refresh.
|
||||
3. Starting and stopping recording changes the privacy indicator promptly and
|
||||
names the client.
|
||||
4. Muting during recording leaves the access indicator visible.
|
||||
5. A Pulse restart clears stale devices/streams and recovers without restarting
|
||||
Quickshell.
|
||||
6. A missing source leaves output controls fully functional.
|
||||
7. Screen sharing works through the portal-only PipeWire path while Pulse
|
||||
remains the sole audio server.
|
||||
8. Lock/unlock transitions never expose private application metadata on the
|
||||
lock surface, but active capture remains visibly indicated.
|
||||
9. IPC calls return structured success/refusal and cannot bypass the settings
|
||||
or step-up authority.
|
||||
|
||||
## Done when
|
||||
|
||||
- [ ] Active audio/privacy services and surfaces are original Souveraine AGPL
|
||||
files with no ii widget dependency in their graph.
|
||||
- [ ] Native PulseAudio is the sole audio authority on phone and laptop.
|
||||
- [ ] Real sinks, sources, playback streams, and recording streams are modeled
|
||||
eventfully and recover across daemon restart.
|
||||
- [ ] A persistent truthful privacy indicator identifies active capture clients
|
||||
and distinguishes mute from revocation.
|
||||
- [ ] Owned phone and laptop presentations share semantics without sharing
|
||||
inappropriate layout.
|
||||
- [ ] Agent IPC covers discovery and guarded actions through the common
|
||||
settings/capability policy.
|
||||
- [ ] Portal video works with a real PipeWire transport while `pipewire-pulse`
|
||||
remains absent.
|
||||
- [ ] Pixel 3 microphone capture is verified non-zero through the named
|
||||
`blueline_mic` Pulse source; no raw-ALSA-only success is accepted as the
|
||||
product result.
|
||||
258
docs/tasks/souveraine-settings-ipc-profiles.md
Normal file
258
docs/tasks/souveraine-settings-ipc-profiles.md
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
---
|
||||
task_id: souveraine-settings-authority-001
|
||||
title: "Souveraine settings authority — complete IPC, security policy, and named profiles"
|
||||
status: scoped
|
||||
priority: high
|
||||
phase: design
|
||||
created: 2026-07-18
|
||||
references:
|
||||
- surfaces/quickshell/modules/common/Config.qml
|
||||
- surfaces/quickshell/modules/settings/
|
||||
- surfaces/quickshell/services/StepUpAuth.qml
|
||||
- surfaces/quickshell/modules/common/functions/Session.qml
|
||||
- docs/tasks/souveraine-shell-ecosystem.md
|
||||
- docs/tasks/device-specific-quickshell-profiles.md
|
||||
- docs/tasks/power-indication.md
|
||||
- docs/DECISIONS.md
|
||||
---
|
||||
|
||||
# Souveraine settings authority
|
||||
|
||||
## End goal
|
||||
|
||||
Every supported Souveraine setting is discoverable and operable through one
|
||||
Souveraine-owned settings authority. The settings application, shell surfaces,
|
||||
profiles, the local human, and agents all use the same schema and mutation
|
||||
path. There are no UI-only settings, hidden ad-hoc writes to `Config.options`,
|
||||
or profiles that bypass the security policy.
|
||||
|
||||
This is not a loose `settings.set(any.path, any.value)` escape hatch. It is a
|
||||
typed, audited capability surface:
|
||||
|
||||
- low-risk settings can be adjusted directly by a human or agent;
|
||||
- sensitive settings can be proposed by an agent but only committed by a
|
||||
local human after seeing the exact diff and satisfying step-up;
|
||||
- secret-bearing values are never returned over shell IPC;
|
||||
- a profile is an atomic settings transaction, not a second configuration
|
||||
mechanism;
|
||||
- every refusal returns a structured reason instead of silently doing nothing.
|
||||
|
||||
Build this authority as original Souveraine AGPL code. Existing ii-derived
|
||||
configuration is input to inventory, not an architecture to preserve.
|
||||
|
||||
## Why a schema is load-bearing
|
||||
|
||||
`Config.qml` currently defines values and persistence, while individual
|
||||
settings pages know labels and presentation. That is not enough for an agent
|
||||
or a profile system: neither can safely infer type, range, risk, device scope,
|
||||
or whether a value is a credential from an arbitrary QML property path.
|
||||
|
||||
Create a Souveraine-owned settings schema. Every supported key has one record:
|
||||
|
||||
```text
|
||||
path lock.security.allowPowerFromLock
|
||||
type bool
|
||||
default false
|
||||
scope common | phone | laptop | device
|
||||
risk ambient | personal | physical | admin | secret
|
||||
mutability direct | propose-only | human-only | read-only
|
||||
profileEligible true
|
||||
requires [capabilities or companion settings]
|
||||
conflicts [mutually exclusive settings]
|
||||
validation enum/range/pattern/custom validator
|
||||
description human- and agent-readable intent
|
||||
```
|
||||
|
||||
The registry is authoritative. A config key without schema metadata is treated
|
||||
as internal and is not exposed over IPC. CI fails when a user-facing setting is
|
||||
added to a settings page without a schema record and IPC reachability test.
|
||||
|
||||
## One settings service, one mutation path
|
||||
|
||||
Create an original `SettingsService.qml` (or equivalent owned service) that
|
||||
owns schema lookup, validation, authorization, persistence, audit, profiles,
|
||||
and change notification. Settings pages stop assigning directly to
|
||||
`Config.options.*`; they call this service just like agents do.
|
||||
|
||||
The service exposes in-process methods for QML and an IPC adapter. Quickshell
|
||||
IPC only reliably transports declared primitive types, so structured payloads
|
||||
and results cross as JSON strings, following the proven `apps` and `dock`
|
||||
surfaces.
|
||||
|
||||
Proposed IPC target: `settings`.
|
||||
|
||||
```text
|
||||
settings.schema() -> all non-secret metadata
|
||||
settings.describe(path) -> metadata + effective value
|
||||
settings.get(path) -> effective value (redacted if secret)
|
||||
settings.list(prefix) -> settings under a namespace
|
||||
settings.set(path, jsonValue, reason) -> direct write or structured refusal
|
||||
settings.propose(path, jsonValue, reason) -> immutable pending change
|
||||
settings.pending() -> pending proposals, no secret values
|
||||
settings.history(limit) -> audit history, redacted
|
||||
settings.profileList() -> available profiles
|
||||
settings.profileDescribe(name) -> metadata + expanded diff
|
||||
settings.profilePropose(name, reason) -> pending atomic profile transaction
|
||||
```
|
||||
|
||||
Do not expose `approve`, `authenticate`, or `mintGrant` over IPC. Approval is a
|
||||
local Souveraine surface action. An agent can formulate a change and explain
|
||||
why; it cannot click its own approval dialog or turn a proposal into authority.
|
||||
|
||||
## Authorization policy
|
||||
|
||||
The settings authority evaluates each key's schema risk. The caller never
|
||||
supplies or self-asserts its risk class.
|
||||
|
||||
| Risk | Read | Agent mutation | Human mutation |
|
||||
|---|---|---|---|
|
||||
| `ambient` | allowed | direct, validated, audited | direct |
|
||||
| `personal` | value may be redacted while locked | direct or proposal according to key metadata | direct when unlocked |
|
||||
| `physical` | allowed unless value itself is sensitive | proposal only | local review + `StepUpAuth("physical")` |
|
||||
| `admin` | metadata allowed; value policy per key | proposal only | local review + `StepUpAuth("admin")` |
|
||||
| `secret` | never return the value | never accept plaintext through shell IPC | local credential surface only |
|
||||
|
||||
`lock.security.allowPowerFromLock`, `requirePasswordToPower`, step-up enablement
|
||||
and TTL, suspend/hibernate policy, charge thresholds, and any setting that
|
||||
widens an agent's own authority are never direct agent writes. They are
|
||||
proposal-only even if a broad step-up grant happens to be live. This prevents
|
||||
an unrelated process from racing the IPC socket during a grant window.
|
||||
|
||||
Approval binds to the immutable proposal digest: path(s), old value(s), new
|
||||
value(s), reason, requester, device, and expiry. The local approval surface
|
||||
shows the complete diff before PAM. Authentication approves that exact digest,
|
||||
not a reusable boolean and not a caller-provided token. Locking the session,
|
||||
changing any old value, or reaching expiry invalidates the proposal.
|
||||
|
||||
## Audit and recovery
|
||||
|
||||
Every attempted mutation records:
|
||||
|
||||
- timestamp and device/profile;
|
||||
- caller identity when available (`human`, `agent:<id>`, system component);
|
||||
- path and redacted old/new values;
|
||||
- reason;
|
||||
- outcome (`applied`, `proposed`, `refused`, `expired`, `rolled-back`);
|
||||
- authorization path (direct policy, physical step-up, admin step-up).
|
||||
|
||||
Successful transactions retain an inverse diff so the settings UI can undo a
|
||||
change. Audit is append-only and bounded/rotated; secret material is never
|
||||
written. A failed multi-key transaction rolls back fully and reports the key
|
||||
that failed.
|
||||
|
||||
## Profiles are policy transactions
|
||||
|
||||
Profiles such as the working-name pair “paranoid” and “open” are named,
|
||||
versioned bundles of schema paths and values. Names remain product language to
|
||||
decide later; do not bake those working names into API semantics.
|
||||
|
||||
A profile is not a parallel config file that overwrites `Config.qml`. Applying
|
||||
one expands it against the current effective configuration, validates every
|
||||
key, computes one visible diff, evaluates the highest risk in that diff, and
|
||||
commits atomically through `SettingsService`.
|
||||
|
||||
Profile model:
|
||||
|
||||
```text
|
||||
id / displayName / description / version
|
||||
deviceScopes: common, phone, laptop, optional explicit device IDs
|
||||
values: schema path -> typed value
|
||||
inherits: optional single base profile (cycle rejected)
|
||||
source: built-in | user | managed
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
1. Applying a profile never bypasses per-key authorization. If one key is
|
||||
`physical` or `admin`, the whole transaction becomes a reviewed proposal.
|
||||
2. Unknown, removed, or device-incompatible keys refuse the transaction; they
|
||||
are not silently ignored.
|
||||
3. Profiles contain no secrets. Credential references are separate and remain
|
||||
local.
|
||||
4. The preview names values that will change, values already satisfied, and
|
||||
unsupported capabilities before authentication.
|
||||
5. A profile applies atomically and records one audit transaction plus its
|
||||
expanded per-key diff.
|
||||
6. The active-profile label is descriptive state, not magical inheritance. A
|
||||
manual edit may mark the profile `modified`; it must not be overwritten by a
|
||||
background reapply.
|
||||
7. Agent-created profiles are proposals until a human saves them. Agents may
|
||||
suggest and preview profiles freely.
|
||||
|
||||
## Device profiles are not security profiles
|
||||
|
||||
Do not conflate `phone`/`laptop` surface profiles with a security posture.
|
||||
|
||||
- A **device profile** chooses form factor, available surfaces, dimensions,
|
||||
hardware capabilities, and package manifest.
|
||||
- A **settings profile** changes policy and preferences on a supported device.
|
||||
|
||||
Settings schema records declare their device scope, and profile expansion
|
||||
refuses incompatible keys. A laptop security profile cannot accidentally turn
|
||||
on a phone-only lock keypad or power-button gesture.
|
||||
|
||||
## Human surfaces
|
||||
|
||||
The Souveraine settings application consumes the same schema and service:
|
||||
|
||||
- categories and controls are projected from metadata where practical;
|
||||
- bespoke pages remain valid for rich interactions, but their writes still go
|
||||
through `SettingsService`;
|
||||
- every setting shows whether agents may change it directly, propose it, or
|
||||
never access it;
|
||||
- pending agent proposals have a first-class review surface;
|
||||
- profile preview is a real diff, with risk and required authentication shown;
|
||||
- undo/history is visible rather than hidden in logs.
|
||||
|
||||
The lock surface never hosts general settings approval. A physical/admin change
|
||||
waits until the user is securely unlocked, except for a deliberately designed
|
||||
emergency action whose policy explicitly says otherwise.
|
||||
|
||||
## Implementation shape
|
||||
|
||||
Original AGPL components, names adjustable during build:
|
||||
|
||||
- `services/SettingsSchema.qml` — metadata and validation definitions.
|
||||
- `services/SettingsService.qml` — effective values, transactions, auth policy,
|
||||
persistence, proposals, history, and profiles.
|
||||
- `modules/souveraine/settings/SettingsScope.qml` — `IpcHandler` adapter only;
|
||||
JSON-string transport, no policy duplication.
|
||||
- `modules/souveraine/settings/ProposalReview.qml` — local diff + step-up.
|
||||
- `modules/souveraine/settings/ProfileManager.qml` — list, edit, preview, apply,
|
||||
and modified-state presentation.
|
||||
- a profile store under Souveraine-owned user state, written atomically.
|
||||
|
||||
The existing `Config.qml` `JsonAdapter` may remain the persistence adapter
|
||||
while the migration is underway, but once `SettingsService` owns a key no UI
|
||||
or service may write that key around it. The end state has one authority, not a
|
||||
permanent split brain.
|
||||
|
||||
## Migration rule
|
||||
|
||||
Inventory all current user-facing Config keys first and classify every one.
|
||||
Move whole namespaces through the authority, not individual toggle patches.
|
||||
Security-sensitive lock/session/power settings are the first namespace because
|
||||
the new `allowPowerFromLock` toggle demonstrates why a direct property write is
|
||||
not enough.
|
||||
|
||||
The migration is complete only when every visible settings control is backed
|
||||
by schema and uses the authority. Do not call a generic unvalidated setter a
|
||||
finished IPC implementation.
|
||||
|
||||
## Done when
|
||||
|
||||
- [ ] Every user-facing setting has schema metadata, device scope, validation,
|
||||
risk, and mutability.
|
||||
- [ ] Every settings UI write and agent mutation uses one SettingsService
|
||||
transaction path.
|
||||
- [ ] `settings` IPC offers discovery, read, direct low-risk set, proposal,
|
||||
history, and profile preview/proposal with JSON-string results.
|
||||
- [ ] Secret values never cross IPC, logs, profile files, or audit history.
|
||||
- [ ] Security-widening changes require local review bound to the exact diff;
|
||||
an agent cannot approve its own proposal.
|
||||
- [ ] Profiles validate and apply atomically and cannot bypass a key's policy.
|
||||
- [ ] Phone/laptop device profiles remain distinct from settings/security
|
||||
profiles.
|
||||
- [ ] Every change is audited and successful transactions can be undone.
|
||||
- [ ] CI catches user-facing Config keys or settings controls missing schema and
|
||||
IPC coverage.
|
||||
Loading…
Reference in a new issue