saf: give the panel's next cuts an owner
This commit is contained in:
parent
2bd61ec4b3
commit
184a449731
7 changed files with 441 additions and 12 deletions
|
|
@ -24,6 +24,8 @@ How Souveraine is built, and why. For whoever reads it, human or agent. When thi
|
||||||
- [session start](surface/02-session-start.md). One package-owned dependency graph from compositor socket to authority to shell.
|
- [session start](surface/02-session-start.md). One package-owned dependency graph from compositor socket to authority to shell.
|
||||||
- [USB Hands](surface/03-usb-hands.md). An armed wire, an optional trackpad, and one acknowledged hand into the attached host.
|
- [USB Hands](surface/03-usb-hands.md). An armed wire, an optional trackpad, and one acknowledged hand into the attached host.
|
||||||
- [agent panel](surface/04-agent-pane.md). One Souveraine conversation, typed thought and action, and truthful controls at the hand.
|
- [agent panel](surface/04-agent-pane.md). One Souveraine conversation, typed thought and action, and truthful controls at the hand.
|
||||||
|
- [agent presence](surface/05-agent-presence.md). One observed session projection, kept rigorously separate from control and permission.
|
||||||
|
- [surface lifetimes](surface/06-surface-lifetimes.md). A small resident shell, optional workers that truly leave memory, and proof before a rewrite.
|
||||||
|
|
||||||
Coming: the rest of identity (the memory filesystem, the ledgers), the nervous system (schedules, the event log), the consciousness cycle, the runtime, federation, a glossary.
|
Coming: the rest of identity (the memory filesystem, the ledgers), the nervous system (schedules, the event log), the consciousness cycle, the runtime, federation, a glossary.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,10 @@ accept selection and never imply that the composer can steer them. Observation
|
||||||
and control can share a menu only when the boundary is visible in words and in
|
and control can share a menu only when the boundary is visible in words and in
|
||||||
behavior.
|
behavior.
|
||||||
|
|
||||||
|
[Agent presence](05-agent-presence.md) owns the collector contract, provider
|
||||||
|
health, activity heuristics, and the future path toward one session service.
|
||||||
|
This chapter owns only how that projection enters the conversation surface.
|
||||||
|
|
||||||
The Panel eventually needs richer active-agent status: substrate reachability,
|
The Panel eventually needs richer active-agent status: substrate reachability,
|
||||||
conversation attachment, primary/subconscious phase, queued interjections, and
|
conversation attachment, primary/subconscious phase, queued interjections, and
|
||||||
the last terminal event. Those facts belong to the Souveraine connection, not
|
the last terminal event. Those facts belong to the Souveraine connection, not
|
||||||
|
|
@ -178,6 +182,10 @@ geometry. Souveraine-owned `AgentMessage`, `ThinkingCard`, `ToolCard`,
|
||||||
it. The next structural cut is an owned Panel host and conversation viewport
|
it. The next structural cut is an owned Panel host and conversation viewport
|
||||||
that consume the same service without copying the adapter's state.
|
that consume the same service without copying the adapter's state.
|
||||||
|
|
||||||
|
Moving the Panel out of the resident shell is a separate lifetime boundary,
|
||||||
|
not a reason to fork its conversation model. [Surface lifetimes](06-surface-lifetimes.md)
|
||||||
|
owns that extraction and its memory/fault proof.
|
||||||
|
|
||||||
That cut should be rehearsed beside the live pane, then swapped once. A QML
|
That cut should be rehearsed beside the live pane, then swapped once. A QML
|
||||||
write-reload loop over the only working chat surface turns each syntax fault
|
write-reload loop over the only working chat surface turns each syntax fault
|
||||||
into a session-wide interruption and can abandon a live turn. Candidate and
|
into a session-wide interruption and can abandon a live turn. Candidate and
|
||||||
|
|
|
||||||
224
saf/surface/05-agent-presence.md
Normal file
224
saf/surface/05-agent-presence.md
Normal file
|
|
@ -0,0 +1,224 @@
|
||||||
|
# Agent presence
|
||||||
|
|
||||||
|
Agent presence answers one narrow question: **which agent sessions can this
|
||||||
|
machine currently observe?** It does not decide which agent a conversation
|
||||||
|
controls, approve a tool on another process's behalf, or turn a terminal
|
||||||
|
session into a model behind the Panel.
|
||||||
|
|
||||||
|
That distinction matters most where the UI is smallest. A Codex process can be
|
||||||
|
running beside Souveraine while the Panel composer still addresses only the
|
||||||
|
selected Souveraine agent. Showing both is useful. Making them look equally
|
||||||
|
selectable is a lie.
|
||||||
|
|
||||||
|
## Three different facts
|
||||||
|
|
||||||
|
Keep these independent even when one menu draws them together:
|
||||||
|
|
||||||
|
- **controlled agent** — the Souveraine agent selected through `/v1/agents`;
|
||||||
|
the Panel can create or resume its conversations and send it a turn;
|
||||||
|
- **observed session** — a recent Souveraine, Claude Code, or Codex record found
|
||||||
|
by the local collector; it may be active, recent, or idle, but observation
|
||||||
|
grants no action;
|
||||||
|
- **provider health** — whether a provider's source was actually inspected.
|
||||||
|
Unavailable is not the same as available with no sessions.
|
||||||
|
|
||||||
|
The controlled agent is a server relationship. Observed activity is a local
|
||||||
|
projection. Provider health is evidence about that projection. Do not infer
|
||||||
|
one from another.
|
||||||
|
|
||||||
|
## What exists now
|
||||||
|
|
||||||
|
The current path is deliberately small and transitional:
|
||||||
|
|
||||||
|
1. `scripts/agent/agent-sessions.sh` inspects recent local records for
|
||||||
|
Souveraine, Claude Code, and Codex and emits one JSON envelope.
|
||||||
|
2. `services/AgentSessions.qml` runs that collector on one cadence, retains the
|
||||||
|
last good envelope, and projects sessions, provider health, active count,
|
||||||
|
staleness, and compact labels.
|
||||||
|
3. `AgentPaneMenu.qml` shows Claude Code and Codex sessions beneath
|
||||||
|
**Running elsewhere · observed only**. Those rows are inert.
|
||||||
|
|
||||||
|
The shell also retains `modules/souveraine/island/Island.qml` and
|
||||||
|
`IslandExpansion.qml`, written against the same service. They are not mounted
|
||||||
|
in the current bar or Panel. They are reusable observer components, not a
|
||||||
|
second live presence surface and not a reason to put agent chrome back above
|
||||||
|
the conversation.
|
||||||
|
|
||||||
|
They are also not abandoned. Their next proper home is the phone's later
|
||||||
|
dynamic top-bar system, once the bar can host more than a fixed row of widgets.
|
||||||
|
The present Panel move lets that larger work wait without making the Island
|
||||||
|
components disposable.
|
||||||
|
|
||||||
|
This is source and current composed-surface behavior. It is not the proposed
|
||||||
|
Rust session daemon. The collector still starts a shell process from QML on
|
||||||
|
each poll.
|
||||||
|
|
||||||
|
## The envelope contract
|
||||||
|
|
||||||
|
Transport may change; these meanings must not:
|
||||||
|
|
||||||
|
- `sessions` is newest first and contains provider identity, stable session
|
||||||
|
identity, a useful label source, last activity, activity state, and only the
|
||||||
|
usage fields the provider actually supplied;
|
||||||
|
- `providers` reports availability, errors, source-specific limits, and the
|
||||||
|
number of sessions admitted from each source;
|
||||||
|
- `active` counts records whose observed activity falls inside the active
|
||||||
|
window;
|
||||||
|
- `ts` says when the envelope was collected, not when every underlying source
|
||||||
|
was updated;
|
||||||
|
- a failed provider degrades inside the envelope instead of aborting the other
|
||||||
|
providers;
|
||||||
|
- a failed whole refresh keeps the last good model and marks it stale instead
|
||||||
|
of replacing it with an authoritative-looking empty list.
|
||||||
|
|
||||||
|
Unknown is a real value. The current shell uses `-1` for an unavailable token
|
||||||
|
measurement and renders an em dash, never zero. Souveraine now persists
|
||||||
|
per-turn usage with assistant messages, but `conversation.json` does not expose
|
||||||
|
an aggregate for the collector, so the presence projection still reports
|
||||||
|
Souveraine session usage as unknown. That projection may be improved; the UI
|
||||||
|
must not manufacture a total in the meantime.
|
||||||
|
|
||||||
|
Claude's local usage is read from a bounded recent tail and is labelled as
|
||||||
|
windowed. Codex's latest token-count record is cumulative for that rollout.
|
||||||
|
Those numbers are not interchangeable merely because both fit in one field.
|
||||||
|
Any combined view must retain the source semantics or omit the comparison.
|
||||||
|
|
||||||
|
## Activity is a heuristic, not cognition
|
||||||
|
|
||||||
|
The present collector derives:
|
||||||
|
|
||||||
|
- `active` from activity within two minutes;
|
||||||
|
- `recent` from activity within one hour;
|
||||||
|
- `idle` from older admitted records.
|
||||||
|
|
||||||
|
These are filesystem/event-age classes. They do not prove that an inference is
|
||||||
|
running, a tool is still alive, an agent is waiting for Casey, or a response is
|
||||||
|
complete. In particular, there is no synthetic `waiting` state. Waiting for a
|
||||||
|
permission decision requires a real request lifecycle; timestamps cannot stand
|
||||||
|
in for it.
|
||||||
|
|
||||||
|
The Panel's own active-turn, primary/subconscious phase, cancellation, and
|
||||||
|
terminal event must continue to come from the Souveraine stream described in
|
||||||
|
[the agent panel](04-agent-pane.md). Presence may corroborate that state. It
|
||||||
|
must not overwrite it.
|
||||||
|
|
||||||
|
## Where presence belongs
|
||||||
|
|
||||||
|
The close conversation surface puts observed external sessions inside the
|
||||||
|
footer's agent menu because that is where mistaken control is easiest to
|
||||||
|
prevent: selectable Souveraine agents first, an explicit divider, then inert
|
||||||
|
external rows.
|
||||||
|
|
||||||
|
A bar, island, overview, or diagnostics page may project the same service when
|
||||||
|
the device has room and the projection answers a real glance question. On a
|
||||||
|
phone, permanent agent-session chrome competes with system state and was
|
||||||
|
rejected on glass. Absence from the bar is therefore a product decision, not a
|
||||||
|
collection failure.
|
||||||
|
|
||||||
|
No surface may:
|
||||||
|
|
||||||
|
- label a discovered process as controllable without an admitted action path;
|
||||||
|
- show unavailable providers as zero sessions;
|
||||||
|
- imply that recency means work is still running;
|
||||||
|
- expose conversation text, prompts, repository paths, or tool payloads merely
|
||||||
|
to make presence richer;
|
||||||
|
- start its own provider poll when `AgentSessions` already owns the projection.
|
||||||
|
|
||||||
|
## The later dynamic bar
|
||||||
|
|
||||||
|
The phone's top bar should ultimately be an extensible host whose components
|
||||||
|
can enter, compact, expand, yield, and leave according to live state. Agent
|
||||||
|
presence is one such component, beside notifications, media, connectivity,
|
||||||
|
power, privacy, and other device facts. A collection of independent widgets
|
||||||
|
all changing width is not that system.
|
||||||
|
|
||||||
|
Before the Island is mounted again, the bar needs a shared contract for:
|
||||||
|
|
||||||
|
- component identity, priority, disclosure class, and device eligibility;
|
||||||
|
- resting, compact, attention, expanded, and hidden forms;
|
||||||
|
- one arbiter for horizontal space and collisions;
|
||||||
|
- preemption and return when a higher-priority event arrives;
|
||||||
|
- dwell, decay, and animation timing so rapid events do not thrash geometry;
|
||||||
|
- tap, long-press, dismiss, and expansion ownership;
|
||||||
|
- lock-state redaction and a safe minimal form;
|
||||||
|
- a stable overflow or secondary surface when several components deserve
|
||||||
|
attention at once;
|
||||||
|
- component failure that removes one projection without taking down the bar.
|
||||||
|
|
||||||
|
`Island.qml` and `IslandExpansion.qml` are useful first clients for that host:
|
||||||
|
they already separate a compact morph from expanded detail and consume the
|
||||||
|
shared presence projection. They do not yet define the host protocol, arbitrate
|
||||||
|
against neighbours, or prove the phone form on glass. The dynamic bar is a
|
||||||
|
larger surface task carried here until it has enough implementation scope to
|
||||||
|
need its own SAF chapter; the old fixed bar placement is not its prototype by
|
||||||
|
default.
|
||||||
|
|
||||||
|
## Permission is a different authority
|
||||||
|
|
||||||
|
The earlier island exploration considered Claude hook installation and
|
||||||
|
Allow/Deny controls. None of that is present in Souveraine's current path. The
|
||||||
|
collector does not edit `~/.claude/settings.json`; there is no permission
|
||||||
|
bridge; observer rows do not jump to or command external terminals.
|
||||||
|
|
||||||
|
If permission control is built later, it needs more than an attractive card:
|
||||||
|
|
||||||
|
- the request must name the exact provider session, tool, arguments, and age;
|
||||||
|
- the producer and target must be authenticated strongly enough for the
|
||||||
|
consequence of the action;
|
||||||
|
- allow-once, deny, expiry, cancellation, and duplicate delivery need explicit
|
||||||
|
states;
|
||||||
|
- the decision and its delivery result must enter the audit trail;
|
||||||
|
- provider failure must fall back to that provider's normal safe behavior;
|
||||||
|
- a broad bypass or allow-all posture requires a separately admitted policy,
|
||||||
|
not a more convenient button.
|
||||||
|
|
||||||
|
Until that path is owned and attested, presence stays read-only.
|
||||||
|
|
||||||
|
## The intended service
|
||||||
|
|
||||||
|
One long-lived session service remains the destination. It should replace the
|
||||||
|
poll subprocess, not change the envelope under every surface. The proposed
|
||||||
|
Unix socket at `$XDG_RUNTIME_DIR/souveraine-sessions.sock` is a candidate
|
||||||
|
transport, not proof that the daemon exists.
|
||||||
|
|
||||||
|
The service needs:
|
||||||
|
|
||||||
|
- one cadence and one adapter per provider;
|
||||||
|
- event-driven updates where a provider supports them, with bounded scans as a
|
||||||
|
fallback;
|
||||||
|
- provider-specific provenance and measurement semantics preserved in the
|
||||||
|
normalized record;
|
||||||
|
- last-good/stale behavior at both provider and whole-envelope level;
|
||||||
|
- stable session identity across refreshes;
|
||||||
|
- bounded resource use and no transcript-content collection merely for a
|
||||||
|
presence label;
|
||||||
|
- an authenticated, separate action channel if external control is ever
|
||||||
|
admitted.
|
||||||
|
|
||||||
|
Souveraine's own session and usage facts should eventually be projected from
|
||||||
|
the substrate directly rather than rediscovered through files written for
|
||||||
|
persistence. Claude and Codex adapters remain local observers unless their
|
||||||
|
providers expose a stronger owned event path.
|
||||||
|
|
||||||
|
## Proof boundary
|
||||||
|
|
||||||
|
Presence work is proven in layers:
|
||||||
|
|
||||||
|
1. **source** — each provider parser is fixture-tested, malformed timestamps do
|
||||||
|
not become plausible epoch-zero state, and provider failure still emits a
|
||||||
|
valid envelope;
|
||||||
|
2. **projection** — one service retains last-good state, marks staleness, and
|
||||||
|
preserves unknown/windowed/cumulative measurement semantics;
|
||||||
|
3. **surface** — external sessions render under an explicit observed-only
|
||||||
|
boundary and cannot be selected or controlled;
|
||||||
|
4. **installed** — the versioned package owns the collector/service/component
|
||||||
|
files used by the running shell;
|
||||||
|
5. **live provider** — a real session enters and leaves each activity class,
|
||||||
|
and a deliberately unavailable provider is visibly different from an empty
|
||||||
|
one;
|
||||||
|
6. **authority**, if ever added — an attested decision reaches only the named
|
||||||
|
request and is recorded end to end.
|
||||||
|
|
||||||
|
The current implementation has the polling envelope and Panel projection. The
|
||||||
|
Rust daemon, aggregate Souveraine usage projection, provider permission path,
|
||||||
|
and cross-provider control are not yet true.
|
||||||
194
saf/surface/06-surface-lifetimes.md
Normal file
194
saf/surface/06-surface-lifetimes.md
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
# Surface lifetimes
|
||||||
|
|
||||||
|
The shell needs a memory budget and failure boundaries, not a superstition
|
||||||
|
about which UI language is pure. Permanent state, optional presentation, and
|
||||||
|
authority must have named owners and observable lifetimes. If closing a heavy
|
||||||
|
surface leaves its objects and pages resident in the only process holding the
|
||||||
|
lock screen, the surface did not meaningfully go away.
|
||||||
|
|
||||||
|
## Evidence that opened this question
|
||||||
|
|
||||||
|
The daily-driver phone has 3.5 GB RAM. Three measurements from August 2026
|
||||||
|
frame the risk without pretending to be a fresh baseline:
|
||||||
|
|
||||||
|
- QuickShell reached about 610 MB RSS during the Live2D experiment;
|
||||||
|
- the summoned WebKit face added about 283 MB RSS in its own process;
|
||||||
|
- a separate dynamic-QML/per-stream rendering storm drove QuickShell to about
|
||||||
|
952 MB anonymous RSS before the kernel killed it.
|
||||||
|
|
||||||
|
These observations do not prove that ordinary QML costs 952 MB, that WebKit is
|
||||||
|
always too expensive, or that a Rust surface is automatically small. They do
|
||||||
|
prove that an optional renderer can consume a material fraction of the phone's
|
||||||
|
memory and that a storm inside the resident QuickShell process shares a
|
||||||
|
failure domain with essential session UI.
|
||||||
|
|
||||||
|
The numbers must be remeasured against exact package revisions and process
|
||||||
|
trees before they become a budget.
|
||||||
|
|
||||||
|
## The resident core
|
||||||
|
|
||||||
|
The resident shell keeps only surfaces and connections that must survive the
|
||||||
|
loss of optional presentation:
|
||||||
|
|
||||||
|
- sessiond heartbeat and the secure session-lock handoff;
|
||||||
|
- the lock surface and lock-tier disclosure gate;
|
||||||
|
- display, idle, and device-state projections needed to remain safe;
|
||||||
|
- the small gesture and power paths required to recover or close a surface;
|
||||||
|
- a minimal system-status/recovery indication.
|
||||||
|
|
||||||
|
The resident core is not a second authority. Sessiond remains the decision
|
||||||
|
owner for lock, power, and admitted device action; the shell renders its state
|
||||||
|
and carries named requests. [Session start](02-session-start.md) owns the
|
||||||
|
package and systemd graph that brings compositor, authority, and shell up in
|
||||||
|
order.
|
||||||
|
|
||||||
|
The secure lock path must not be conditionally absent while a shell reload is
|
||||||
|
in flight. Optional-surface work may not reopen the already-known race where a
|
||||||
|
new shell requests a lock before the old holder has transferred or released
|
||||||
|
it.
|
||||||
|
|
||||||
|
## Optional means separately disposable
|
||||||
|
|
||||||
|
The agent Panel, Live2D presence, web content, large explorers, and future
|
||||||
|
special renderers are optional surfaces. Each needs:
|
||||||
|
|
||||||
|
- a named package and executable or explicit in-process owner;
|
||||||
|
- one startup trigger and one authority that may request presentation;
|
||||||
|
- a shutdown rule after close, idle, lock transition, or resource pressure;
|
||||||
|
- a state restoration key whose authority lives outside the renderer;
|
||||||
|
- a disclosure class and locked-state behavior;
|
||||||
|
- a resource line measured while closed, opening, active, and closing;
|
||||||
|
- a supervisor policy and a visible failure event.
|
||||||
|
|
||||||
|
A QML `Loader` is useful for avoiding construction and destroying object
|
||||||
|
graphs. It is not proof that allocator pages returned to the operating system,
|
||||||
|
and it cannot stop a rendering storm from killing the process that owns it.
|
||||||
|
Call that path lazy only after object lifetime is verified; call memory
|
||||||
|
released only after the OS measurement falls.
|
||||||
|
|
||||||
|
For expensive surfaces, a supervised process is the preferred boundary. When
|
||||||
|
the process exits, its private memory and faults leave with it. The resident
|
||||||
|
shell may retain a small launch/status projection, never the heavy renderer's
|
||||||
|
state graph.
|
||||||
|
|
||||||
|
## The Panel is the first extraction
|
||||||
|
|
||||||
|
The agent Panel is the strongest first worker candidate because its authority
|
||||||
|
already lives elsewhere:
|
||||||
|
|
||||||
|
- the Souveraine server owns agents, conversations, messages, itinerary,
|
||||||
|
cancellation, interjection, and replay;
|
||||||
|
- sessiond owns session/lock/device authority;
|
||||||
|
- the Panel owns presentation, input collection, transient selection, and
|
||||||
|
viewport state.
|
||||||
|
|
||||||
|
An extracted `souveraine-agent-surface` must therefore consume the same typed
|
||||||
|
server contract described in [the agent panel](04-agent-pane.md). It must not
|
||||||
|
copy conversations into a new local authority or become a second writer during
|
||||||
|
candidate testing.
|
||||||
|
|
||||||
|
Its lifecycle should be explicit:
|
||||||
|
|
||||||
|
1. an unlocked, admitted presentation request launches the version selected by
|
||||||
|
the installed surface package;
|
||||||
|
2. the worker authenticates to the local Souveraine endpoint and attaches only
|
||||||
|
after Casey selects or explicitly resumes a conversation;
|
||||||
|
3. close detaches presentation and gives the worker a short bounded grace for
|
||||||
|
non-authoritative UI state;
|
||||||
|
4. the supervisor ends the worker after that grace;
|
||||||
|
5. reopen reconstructs from substrate truth and may restore harmless viewport
|
||||||
|
state separately;
|
||||||
|
6. lock immediately hides Personal-class content and follows the declared
|
||||||
|
stop/blank policy even if the worker is stuck.
|
||||||
|
|
||||||
|
During an active stream, a killed worker must not cancel the server turn unless
|
||||||
|
Casey issued cancel. The substrate continues or records its terminal state;
|
||||||
|
reopening reattaches and backfills. Conversely, a worker must not remain alive
|
||||||
|
forever merely because a server stream forgot to close. Presentation lifetime
|
||||||
|
and inference lifetime are related state machines, not one process lifetime.
|
||||||
|
|
||||||
|
## Fault containment
|
||||||
|
|
||||||
|
The resident shell needs a small supervisor projection for each optional
|
||||||
|
surface: stopped, starting, ready, active, stopping, failed, and backoff. A
|
||||||
|
crash becomes an event with the package version and last lifecycle edge. It
|
||||||
|
must not silently relaunch in a tight loop or take the session lock with it.
|
||||||
|
|
||||||
|
The decisive fault tests are physical:
|
||||||
|
|
||||||
|
- kill the Panel during streamed text and during a large tool return;
|
||||||
|
- feed a candidate QML version that fails to load;
|
||||||
|
- wedge the worker so it ignores close;
|
||||||
|
- lock while Personal-class content is visible;
|
||||||
|
- exhaust the worker's memory budget without exhausting the resident core.
|
||||||
|
|
||||||
|
In every case the lock surface, power path, sessiond heartbeat, and recovery
|
||||||
|
control must remain available. A screenshot after restart is not fault proof.
|
||||||
|
|
||||||
|
## Versioned delivery on every body
|
||||||
|
|
||||||
|
The laptop and phone receive published packages from Gitea. A surface split is
|
||||||
|
complete only when the package graph installs compatible versions and the
|
||||||
|
systemd/session start path selects them consistently. Hand-placing a worker on
|
||||||
|
one device proves a diagnosis at most; it is not the fix future installs will
|
||||||
|
receive.
|
||||||
|
|
||||||
|
The core and optional-surface protocol must be versioned. Compatibility needs
|
||||||
|
an explicit range or handshake so a newer Panel cannot silently interpret an
|
||||||
|
older substrate event shape. Package upgrade stages a candidate; adoption and
|
||||||
|
restart remain explicit where a live conversation or lock handoff could be
|
||||||
|
disturbed. The last working surface stays available until the candidate reaches
|
||||||
|
ready state.
|
||||||
|
|
||||||
|
Gitea Actions and ArchDev own compilation and package artifacts. Local checks
|
||||||
|
may parse QML, format Rust, validate manifests, and exercise fixtures; they do
|
||||||
|
not replace the package result.
|
||||||
|
|
||||||
|
## Native Rust is a measured option
|
||||||
|
|
||||||
|
A Rust Wayland client could replace some or all of QuickShell, but it still has
|
||||||
|
to own layer-shell/session-lock protocols, rendering, text, input, animation,
|
||||||
|
accessibility, service integration, and recovery. Rust does not remove the
|
||||||
|
need for resident/optional process boundaries, and a native screenshot says
|
||||||
|
nothing about steady memory or fault behavior.
|
||||||
|
|
||||||
|
The useful spike is deliberately small: one native layer-shell card, one typed
|
||||||
|
sessiond-fed state, one package, and measurements for RSS/PSS, launch latency,
|
||||||
|
and failure. It does not take the lock, replace the shell, or grow a parallel
|
||||||
|
settings authority. Compare it against the extracted QuickShell worker under
|
||||||
|
the same workload before choosing a rewrite.
|
||||||
|
|
||||||
|
## Measurement record
|
||||||
|
|
||||||
|
Every budget line should name:
|
||||||
|
|
||||||
|
- device and available RAM;
|
||||||
|
- source commit, package version, and protocol version;
|
||||||
|
- process tree and which surfaces are constructed;
|
||||||
|
- RSS and PSS after a defined settle time;
|
||||||
|
- peak during a defined action, including a representative streamed tool turn;
|
||||||
|
- memory after close and after worker exit;
|
||||||
|
- launch-to-ready latency;
|
||||||
|
- result of the relevant kill/lock/reopen test.
|
||||||
|
|
||||||
|
Measure at least resident idle, Panel closed, Panel open and idle, active text
|
||||||
|
stream, large tool payload, Live2D closed/open, and post-close. A single `ps`
|
||||||
|
line without surface state is anecdote, not a budget.
|
||||||
|
|
||||||
|
## Proof and present boundary
|
||||||
|
|
||||||
|
The path is complete only when:
|
||||||
|
|
||||||
|
1. the resident and optional sets are explicit in source and packages;
|
||||||
|
2. closing the Panel ends its worker and the OS-visible memory leaves;
|
||||||
|
3. killing or wedging that worker leaves lock, heartbeat, power, and recovery
|
||||||
|
alive;
|
||||||
|
4. locked-state disclosure is exercised, not inferred from a conditional;
|
||||||
|
5. reopen restores the authoritative conversation without duplicating a turn;
|
||||||
|
6. Gitea emits the versioned core and surface packages used by both laptop and
|
||||||
|
phone;
|
||||||
|
7. a Rust rewrite decision, if made, cites comparable measurements.
|
||||||
|
|
||||||
|
None of that extraction is true yet. The current Panel remains inside the
|
||||||
|
resident QuickShell process; the August numbers are historical observations;
|
||||||
|
and the Rust path remains a bounded experiment, not an adopted shell plan.
|
||||||
|
|
@ -132,9 +132,9 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
// "—" where a provider does not report tokens. Rendering a
|
// "—" where a provider does not report tokens. Rendering a
|
||||||
// 0 would be a measurement claim we cannot back: the
|
// 0 would be a measurement claim we cannot back. The
|
||||||
// Souveraine substrate records TokenUsage but nothing calls
|
// substrate persists per-turn usage, but this presence
|
||||||
// assistant_with_usage yet (TASK-67). An em dash is the
|
// projection does not aggregate it. An em dash is the
|
||||||
// honest glyph for "not measured".
|
// honest glyph for "not measured".
|
||||||
StyledText {
|
StyledText {
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
|
|
||||||
|
|
@ -136,11 +136,12 @@ codex_json() {
|
||||||
|
|
||||||
# ------------------------------------------------------------ souveraine ----
|
# ------------------------------------------------------------ souveraine ----
|
||||||
# ~/.souveraine/server/agents/<agent>/conversations/<conv>/conversation.json
|
# ~/.souveraine/server/agents/<agent>/conversations/<conv>/conversation.json
|
||||||
# carries updated_at + message_count. It does NOT carry token usage: the
|
# carries updated_at + message_count. It does NOT carry aggregate token usage:
|
||||||
# substrate records `TokenUsage` but `assistant_with_usage` has zero callers
|
# the substrate persists per-turn `TokenUsage` in its message record, while
|
||||||
# (TASK-67). We report -1 for tokens rather than 0, because 0 is a measurement
|
# this bounded presence scan intentionally reads only conversation metadata.
|
||||||
# and -1 is an admission. The day TASK-67 lands, this starts reporting real
|
# We report -1 rather than 0, because 0 is a measurement and -1 is an
|
||||||
# numbers and nothing else has to change.
|
# admission. A direct substrate projection can fill the fields later without
|
||||||
|
# changing the surface contract.
|
||||||
souveraine_json() {
|
souveraine_json() {
|
||||||
local dir="$HOME/.souveraine/server/agents"
|
local dir="$HOME/.souveraine/server/agents"
|
||||||
[ -d "$dir" ] || { echo '{"available":false,"error":"no ~/.souveraine"}'; return; }
|
[ -d "$dir" ] || { echo '{"available":false,"error":"no ~/.souveraine"}'; return; }
|
||||||
|
|
|
||||||
|
|
@ -113,10 +113,10 @@ Singleton {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Total tokens for a session, or -1 when the provider genuinely does not
|
// Total tokens for a session, or -1 when the provider genuinely does not
|
||||||
// report them. -1 is deliberate: the Souveraine substrate records TokenUsage
|
// report them. -1 is deliberate: Souveraine persists per-turn TokenUsage,
|
||||||
// but `assistant_with_usage` has zero callers (TASK-67), so a 0 here would
|
// but the conversation.json metadata inspected by the presence collector
|
||||||
// be a measurement claim we cannot back. Surfaces must render -1 as "—",
|
// does not aggregate it. A 0 here would be a measurement claim we cannot
|
||||||
// never as zero.
|
// back. Surfaces must render -1 as "—", never as zero.
|
||||||
function sessionTokens(s) {
|
function sessionTokens(s) {
|
||||||
if (!s)
|
if (!s)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue