59/60 and the bug dump: what landed the day her face went on the glass
TASK-59 becomes a record of five bugs that each presented as something else — the missing #live_talk element, --app-id doing nothing, the GL context claimed before the canvas was sized, posture wired to a function that does not exist, and a feed that dropped its own reader for being slow. Plus the furniture role, input regions, gaze, and what the rig costs next. TASK-60: the cards were zero pixels wide, and the capture-hang theory is retracted — the session had been left locked by a test. DUMP: 3/4/5 closed, 7 retracted with the trap that produced it, 8/9/10 new.
This commit is contained in:
parent
d62ae3fd77
commit
528d290ba6
3 changed files with 269 additions and 5 deletions
|
|
@ -48,7 +48,53 @@ model can carry it out without re-deriving context.
|
|||
the global or ship a recorder that speaks ext-capture. Severity: medium,
|
||||
this gates the radial-dial record entry.
|
||||
|
||||
## Recording — narrowed 2026-08-07
|
||||
## Resolved 2026-08-07
|
||||
|
||||
Items 3, 4 and 5 are closed, and item 7 below turned out to be a false lead.
|
||||
|
||||
- **3. The avatar renders nothing — FIXED.** Not the loopback origin. The page
|
||||
omitted `#live_talk`, which the bundled character layer reads every frame;
|
||||
it threw on the first update after the model and all four textures had
|
||||
loaded. See TASK-59's 2026-08-07 section for the five bugs in that chain.
|
||||
- **4. A second app splits instead of minting a zone — FIXED and verified.**
|
||||
Three apps → zones 1/2/3. The fix (`60ff764`) had been committed and never
|
||||
pushed, so the phone had never had it. **The null `app_id`/`title` in the
|
||||
`workspaces` report was real and is also fixed** — the report calls them
|
||||
"the join key" and nothing had ever written them — but it was not what broke
|
||||
the cards (see 7).
|
||||
- **5. Does viewtop serve wlr-screencopy — YES.** `grim` works. It hangs only
|
||||
behind a lock, which is the capture gate doing its job.
|
||||
|
||||
- **7. Screencopy hangs / the cards are blocked on it — WRONG, and here is the
|
||||
trap.** The compositor was refusing captures with *"no client captures the
|
||||
screen behind a lock screen"* because the session had been left locked by a
|
||||
test, while `logind` reported `LockedHint=no`. **Check `locked` in `state`
|
||||
before concluding anything from a capture failure.** The cards were zero
|
||||
pixels wide; see TASK-60.
|
||||
|
||||
## New, 2026-08-07
|
||||
|
||||
8. **The pill strands a pose.** A partial slide up leaves the app scaled small
|
||||
and it takes another pull on the pill to get it back. `onCanceled` already
|
||||
exists on the rail and already calls `endPull(false)` — **that is not the
|
||||
hole**, and a duplicate handler added there fails the whole QML module
|
||||
("Property value set multiple times") and takes the shell down. Cause
|
||||
unfound. Casey also wants the partial slide gated on speed *and* length and
|
||||
then committed, iOS-style, with no backing-off state at all.
|
||||
|
||||
9. **Side panels glitch on the way out.** The keyboard half is fixed — the
|
||||
drawer cleared `oskOpen` on close and `SidebarLeft` never did, so the OSK
|
||||
outlived the only text field it was serving. The visual glitch on leaving is
|
||||
still uncharacterised.
|
||||
|
||||
10. **The terminal cannot keep the keyboard.** It disappears while the cursor
|
||||
is in a field and the right panel closes with it. Note a terminal never
|
||||
requests text-input so the OSK must be summoned, and `oskOpen` **flaps by
|
||||
design** because the OSK self-hides whenever input-method focus drops —
|
||||
never gate a persistent surface on it. Being the mirror image of 9 suggests
|
||||
one focus-handoff bug, not two.
|
||||
|
||||
## Recording — narrowed 2026-08-07 (superseded by "Resolved" above)
|
||||
|
||||
7. **Screencopy hangs while mission control is open, and that is why the
|
||||
cards never appear.** Measured on blueline: `grim` returns a file in under
|
||||
|
|
|
|||
|
|
@ -1,7 +1,167 @@
|
|||
# TASK 59 — her face on the glass: a Live2D presence for Annie
|
||||
|
||||
**Status: 2026-08-05 — phase 1 PASSED on hardware. Cubism renders on blueline at
|
||||
~58 fps in the engine wry wraps.** The gate this task set for itself is cleared;
|
||||
**Status: 2026-08-07 — SHE IS ON THE GLASS.** She draws, she is furniture on
|
||||
home rather than an app, she takes touch only on her silhouette, she follows a
|
||||
finger anywhere on the panel, holding her records and sends through the
|
||||
existing STT, double-tapping her dismisses her, and locking the phone sends her
|
||||
away. Q0/Q1/Q1a/Q3/Q4 are answered in code. What remains is her *own* face
|
||||
(TASK-17-shaped, see "the rig is next") and idle behaviour (Q2).
|
||||
|
||||
## 2026-08-07 — what landed, and the five bugs that were in the way
|
||||
|
||||
Every one of these presented as something else, which is the reason they are
|
||||
written down rather than summarised.
|
||||
|
||||
1. **The rig never drew, and it was one missing element.** `live2d.js` is not
|
||||
only the Cubism runtime — it is the reference's webpack bundle with the
|
||||
character layer inside, and `Live2DModel.update()` reads
|
||||
`#live_talk`'s value **every frame** as its motion-state slot. Our page
|
||||
omitted it, so it threw `TypeError: null is not an object` on the first
|
||||
update — *after* the runtime had logged its banner and loaded the model and
|
||||
all four textures. Assets 200, WebGL live, rAF at 60, no error reaching
|
||||
Rust, blank canvas. Exactly the failure this task predicted would cost an
|
||||
afternoon, and it did.
|
||||
**`#live_talk` starts at `"0"`, not the reference's `"1"`** — `"1"` means
|
||||
*start a talk motion*, so she came up miming speech with no voice behind it.
|
||||
2. **`--app-id` was a no-op.** `set_prgname` ran *after* GTK had already created
|
||||
the surface, so the compositor saw `souveraine-web` and window rules could
|
||||
only ever match the title. It has to run before the event loop is built.
|
||||
Without this the compositor cannot recognise her at all, so the whole role
|
||||
below is unreachable.
|
||||
3. **Claiming the GL context for `preserveDrawingBuffer` must happen after the
|
||||
canvas is sized.** Before it, the context is born at the default 300x150 and
|
||||
`gl.viewport` stays there while `fit()` grows the buffer to the panel — the
|
||||
rig then draws into a 300x150 corner of a 1080x1994 buffer, and because GL's
|
||||
origin is bottom-left she appears as a thumbnail in the bottom-left of the
|
||||
screen. Same cause as the silhouette sampling reading 9 lit cells of 864.
|
||||
4. **`posture()` called `window.live2dMotion`, which does not exist.** Nine
|
||||
states advertised to her in the prompt and wired to nothing. The bundle
|
||||
exposes two levers: `#live_talk`, and its own head/body hit test. The nine
|
||||
collapse onto those — speaking talks, idle rests, and the rest are a look:
|
||||
head for attention, body for effort. The bundle rate-limits its own hit
|
||||
reaction to ~8 s, which is why a burst of tags reads as one shift.
|
||||
5. **The gaze feed died of its own speed.** `Feeds::publish` dropped any
|
||||
subscriber whose channel was `Full`, so ~25 pushes/s filled the queue faster
|
||||
than a QML socket drained it and the shell was unsubscribed inside the first
|
||||
burst of a drag — never told. An external probe that read faster kept
|
||||
working, which is what made it look like the shell's bug. A full channel now
|
||||
skips the message; only `Disconnected` drops a subscriber.
|
||||
(Also: Quickshell's `Socket` emits `onConnectionStateChanged`, not
|
||||
`onConnectedChanged`, so the subscribe was never sent.)
|
||||
|
||||
### The role — Q1 answered in the compositor
|
||||
|
||||
`Role::App | Role::Furniture`, decided at the **first commit** and not at map,
|
||||
because `xdg_toplevel` is created before the client sends `set_app_id`. The old
|
||||
path minted a zone, moved the strip, took the keyboard and told the dock about
|
||||
a window it had not yet identified. Furniture (`org.souveraine.face`) takes no
|
||||
zone, is announced to nobody, wears no frame, keeps its own size, and hangs
|
||||
from the **top** of the zone with all the leftover room reserved below her —
|
||||
Casey wants that space for what she shares (data, a page, something of hers).
|
||||
|
||||
`state` reports `furniture` and its `input_rects`, because neither is visible
|
||||
on the glass and a face that swallows the screen looks identical to one that
|
||||
does not.
|
||||
|
||||
### Her input region — and the compositor bug under it
|
||||
|
||||
She is a transparent surface the width of the panel, so without an input region
|
||||
she takes every contact on home. The page samples her own alpha on a 24x36 grid
|
||||
and reports row-runs; the host installs them with `input_shape_combine_region`.
|
||||
Measured: 36-47 rectangles, ~24% of her bounding box.
|
||||
|
||||
**`windows_under` never consulted `wl_surface.set_input_region`** — so the
|
||||
client could declare whatever it liked and viewtop still handed it every
|
||||
contact. Fixing that also stopped GTK client-side-decoration shadows from
|
||||
eating taps meant for what is behind them.
|
||||
|
||||
### Gaze — Q3 answered, and it is better than tracking-on-touch
|
||||
|
||||
A `gaze` verb on the control socket: its own feed (the strip changes when the
|
||||
world does; a contact changes tens of times a second), throttled to 40 ms,
|
||||
physical contacts only, and the release is never dropped or she keeps staring
|
||||
at where the finger last was. The shell forwards it as a synthetic
|
||||
`mousemove` on the canvas, so `live2d.js`'s own damping does the work.
|
||||
|
||||
**Synthetic is the point.** Her input region means the compositor deliberately
|
||||
does *not* hand her those contacts — this lets her watch a finger she is not
|
||||
being given, anywhere on the panel, rather than only when a drag starts on her.
|
||||
|
||||
### Q1a — holding her to talk works, and is the wrong affordance
|
||||
|
||||
Press and hold past 350 ms → `pw-record` at 16k mono s16 → release →
|
||||
`souveraine-stt --file` → `Souveraine.send()`, so the sidebar logs it and the
|
||||
reply streams back to her bubble. Verified end to end.
|
||||
**Whisper wraps its output with newlines** and the transcript arrives through a
|
||||
`SplitParser` on `"\n"`, so it must be collapsed or one utterance becomes four
|
||||
turns.
|
||||
|
||||
Casey, 2026-08-07: *"holding onto her has a different connotation."* The
|
||||
gesture works and should be replaced by explicit controls. Recorded here rather
|
||||
than fixed.
|
||||
|
||||
### Q4 answered: whose she is
|
||||
|
||||
Double tap her to dismiss — the same gesture in the same place that summoned
|
||||
her from the clock, because the clock has faded by then and a double tap on an
|
||||
invisible object is not a route. **Locking sends her away and she stays away**;
|
||||
you come back to the clock and summon her if you want her.
|
||||
|
||||
Gated on `screenLockSecure`, the compositor's ack, **not** `screenLocked`: the
|
||||
request drifts. Measured — `session lock` answered `already-locked` while
|
||||
logind reported `LockedHint=no` and the phone was in use. A face gated on that
|
||||
would have been permanently dismissed with nothing on screen to explain it.
|
||||
|
||||
### The clock yields
|
||||
|
||||
`CookieClock` and `CookieQuote` fade and shrink out when she is up (180 ms out,
|
||||
260 ms back, 0.86 scale — the overview cards' own number, so the device's
|
||||
theatre moves alike), and the faded clock stops being a tap target.
|
||||
`CookieQuote` needed a souveraine override: it is the clock's *sibling* in
|
||||
`ClockWidget`'s Column, and that parent lives in `ii-base`, which never reaches
|
||||
the phone.
|
||||
|
||||
`CookieClock` had been reading `Face.rigPresent` — **a property that does not
|
||||
exist**, left behind when the rig pre-flight check was deleted. It bound to
|
||||
`undefined` for as long as it had been there.
|
||||
|
||||
### Her size is her scale
|
||||
|
||||
The Cubism view fits the rig to the canvas, so shrinking the canvas shrinks
|
||||
*her*; it does not trim the empty margin around her. 640 was tried to cut the
|
||||
~100 px of dead space under her feet and came back *"a tiny version that's
|
||||
scaled odd."* The margin is the rig's own `layout` (`center_y`, `width`) in
|
||||
`model.json` — moving it is a rig change, not a window one. **540x760.**
|
||||
|
||||
### The rig is next, and what it costs
|
||||
|
||||
Casey wants her to look like Annie: blonde twin-tails, teal circuit markings, a
|
||||
six-state sheet (IDLE / ALERT / ENGAGED / PROCESSING / YAWNING / STRAINING)
|
||||
that maps almost 1:1 onto the posture vocabulary already in `Face.qml`.
|
||||
|
||||
**V1 is the face**, not the outfit: Histoire reads as a little girl and not a
|
||||
woman, so shrink the eyes and slim the face with transparency. Hair already
|
||||
reads close. Wings become holographic — "witchy wizard tech woman".
|
||||
|
||||
The real goal is a **pipeline, not a repaint**: strip the rig's parts out by
|
||||
name with their exact UV footprints, rebuild by compositing them back at those
|
||||
footprints, and let agents swap components the way they swap outfits. The
|
||||
rebuild half is what makes swapping real. See TASK-18's notes in the session
|
||||
task list and the ceiling below.
|
||||
|
||||
**Ceiling, so it is not discovered late:** parts are paint; silhouette is mesh.
|
||||
Twin-tails, proportions and the sitting-on-a-book pose need a new rig — and
|
||||
that is a Cubism 2 → 4/5 change, a **different loader**, which also replaces
|
||||
the character layer that reads `#live_talk`.
|
||||
|
||||
**Watch:** the blink/eye-open deformers are authored against the *original* eye
|
||||
geometry, so a smaller eye may not line up with the eyelid sweep. Test by
|
||||
rendering a blink, not by looking at the atlas.
|
||||
|
||||
## 2026-08-05 — phase 1 PASSED on hardware
|
||||
|
||||
**Cubism renders on blueline at ~58 fps in the engine wry wraps.**
|
||||
The gate this task set for itself is cleared;
|
||||
what remains is building the host and making her Annie. From Casey, after
|
||||
finding a Live2D board-girl on a blog he had cloned: *"I want to take a peek at how it
|
||||
functions and see if there's a crossover event to where it could exist on the
|
||||
|
|
|
|||
|
|
@ -1,7 +1,65 @@
|
|||
# TASK 60 — multitasking is a place, not a transition
|
||||
|
||||
**Status: open — design, 2026-08-05.** Written after building the wrong thing
|
||||
and being told so. Casey, on device:
|
||||
**Status: 2026-08-07 — the cards draw.** Zone cards with live previews, a close
|
||||
control and a zone label, verified on hardware. What remains is the swipe
|
||||
*into* it, which is still awkward.
|
||||
|
||||
## 2026-08-07 — the cards were zero pixels wide
|
||||
|
||||
Reported as *"it goes to a blur screen but nothing else"*, and every signal read
|
||||
healthy: `zones 2, windows 1, subscribed true, loader active, item present,
|
||||
opacity 1, progress 1`. The blur was the backdrop; the cards were there and
|
||||
**540 px shorter than nothing** — `item.w: 0, h: 842`.
|
||||
|
||||
`ZoneOverview` took its width from the `Column` it sits in, and a Column is as
|
||||
wide as its widest child. In the drawer the search widget supplies that width;
|
||||
**mission control is the cards alone and has no search**, so the only child left
|
||||
was the loader — whose width came from the column, whose width came from the
|
||||
loader. The cycle resolves to zero. Bound to `panelWindow.width` instead, which
|
||||
is what this surface covers anyway (its mask is `missionBackdrop`, not the
|
||||
drawer's sheet).
|
||||
|
||||
Two things that made it findable, and are worth keeping:
|
||||
|
||||
- **`overview missionControl` and `overview state` verbs.** The one surface
|
||||
reported broken was the only one nothing but a pill swipe could raise, so it
|
||||
could not be inspected or tested. `state` reports what the cards are drawn
|
||||
from, and reading `item.w: 0` beside `column.w: 0` is what located this in
|
||||
one step after a long time spent on wrong theories.
|
||||
- **A false lead worth recording:** the compositor was refusing every capture
|
||||
with `"no client captures the screen behind a lock screen"`, and `grim` hung
|
||||
the same way the cards did. That is *correct* behaviour behind a lock — the
|
||||
session had been left locked by a test. Capture was never the problem. Check
|
||||
`locked` in `state` before concluding anything from a capture failure.
|
||||
|
||||
**Cards are inset** (26 px sides, 12 top) so neighbouring zones show through —
|
||||
full-bleed reads as "you are looking at that app" rather than "here are the
|
||||
places you can go", and leaves nothing on screen saying there ARE neighbours.
|
||||
|
||||
### Still open: the swipe in
|
||||
|
||||
Casey, 2026-08-07: *"the visual style from swiping up into this mode... we lost
|
||||
the consistency... the swipe to this swap is awkward."*
|
||||
|
||||
The machinery exists and is where to look. `ZoneOverview.progress` follows
|
||||
`GlobalStates.zonePullProgress` while the rail is pulling and the state flag
|
||||
takes over on commit — this task's own acceptance is *"no frame where a window
|
||||
is scaled by one and laid out by the other."* Two concrete suspects:
|
||||
|
||||
1. Cards start at `scale 0.6 + 0.4 * share`, chosen to match the scale the
|
||||
rail's `pose` has reached at the multitasking detent. **0.6 is a
|
||||
written-down constant**; if the rail's actual pose there is not 0.6, the
|
||||
card pops to a different size at handoff.
|
||||
2. The inset above makes the card **smaller than the full-bleed window it
|
||||
replaces** at the handoff moment, which may have made that seam worse.
|
||||
Either the rail's pose should end at the inset card's rect, or the inset
|
||||
should animate in after the handoff rather than being there at `share = 0`.
|
||||
|
||||
Needs watching in motion. Screenshots cannot see it.
|
||||
|
||||
## Original — design, 2026-08-05
|
||||
|
||||
Written after building the wrong thing and being told so. Casey, on device:
|
||||
|
||||
> *"Still major issues. We might need to take these concepts we've built back to
|
||||
> the workshop. The scaling doesn't follow the selected app. meaning app#2
|
||||
|
|
|
|||
Loading…
Reference in a new issue