tasks: index 36-40, correct TASK-34's invalid test, add inference tiering task
This commit is contained in:
parent
b24963ad01
commit
4287d8765d
3 changed files with 221 additions and 3 deletions
|
|
@ -1,6 +1,31 @@
|
|||
# TASK 34 — SLPI bring-up sequencing regression
|
||||
|
||||
**Status:** open, raised 2026-07-26. **Size:** one session, mostly bisection.
|
||||
**Status:** NEEDS RE-DIAGNOSIS — the test below is invalid (2026-07-27).
|
||||
**Size:** one session, mostly bisection.
|
||||
|
||||
> **2026-07-27:** measured on the device, `blueline-hexagonrpcd-sdsp` is
|
||||
> **active**, and the sensors work: `monitor-sensor --light` returns live,
|
||||
> changing lux (`0.665771`, `unit: lux`) and iio-sensor-proxy answers
|
||||
> `HasProximity`/`HasAmbientLight`/`HasAccelerometer` = true.
|
||||
>
|
||||
> The symptom below — "no ssc-accel, ssc-proximity, ssc-light in
|
||||
> `/sys/bus/iio/devices`" — **is not a valid test and was never going to be.**
|
||||
> The SSC sensors are not IIO devices. `90-iio-sensor-proxy-ssc.rules` tags
|
||||
> them onto the FastRPC *misc* nodes:
|
||||
>
|
||||
> ```
|
||||
> SUBSYSTEM=="misc", KERNEL=="fastrpc-sdsp*", ENV{IIO_SENSOR_PROXY_TYPE}+="ssc-accel ssc-proximity ssc-light"
|
||||
> ```
|
||||
>
|
||||
> so iio-sensor-proxy reaches them over libssc/FastRPC and they never appear
|
||||
> under `/sys/bus/iio/devices` — healthy or not. That directory holds exactly
|
||||
> two entries on a working device, both PMIC ADCs, which is what it holds
|
||||
> today.
|
||||
>
|
||||
> Whatever happened on 07-26 was real (the service did hit its start limit),
|
||||
> but "no SSC sensor reached userspace" was inferred from a test that cannot
|
||||
> show that. Re-diagnose from the service journal and a live `monitor-sensor`,
|
||||
> not from the IIO device list. **TASK-13 is not blocked on this.**
|
||||
**Repo:** `~/Projects/Pixel3Arch` (`rootfs-overlay/etc/systemd/system`).
|
||||
|
||||
## Symptom
|
||||
|
|
|
|||
188
docs/tasks/40-inference-tiering-sensors.md
Normal file
188
docs/tasks/40-inference-tiering-sensors.md
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
# TASK 40 — Inference tiering for the sensor surfaces
|
||||
|
||||
**Status:** open, gating. Raised 2026-07-27 (Casey, explicitly: the "based on
|
||||
what they might infer" lens). **Size:** decisions first, then small code.
|
||||
**Repos:** `souveraine` (sensord, sessiond, dial QML), `Pixel3Arch`
|
||||
(blueline-edge-sense).
|
||||
|
||||
## The lens, in its own words
|
||||
|
||||
`SECURITY-AUDIT.md` **P1 — inference-first tiering**:
|
||||
|
||||
> Permission classes are defined by **what a capable agent could infer from a
|
||||
> stream, not by what the field literally is.** A contact count, an app-launch
|
||||
> timing log, an ambient noise level, a raw accelerometer reading — each is
|
||||
> "just data" per-field, and each is an inference substrate for a sufficiently
|
||||
> capable model.
|
||||
>
|
||||
> AOSP retrofitted the 200Hz sensor cap and `HIGH_SAMPLING_RATE_SENSORS`
|
||||
> *after* realizing motion sensors infer keystrokes, gait, identity — it was a
|
||||
> gap, then a patch, not first-class design. We model inference as first-class.
|
||||
>
|
||||
> **Application:** every tier assignment must be justified against the
|
||||
> inference lens. "Looks innocent" is not a defense.
|
||||
|
||||
Three things landed or moved in the last day that this has never been applied
|
||||
to. Two are about to start emitting for the first time, which is exactly the
|
||||
moment P1 says to do the work — before the stream flows, not after.
|
||||
|
||||
---
|
||||
|
||||
## 1. The sensor stream is about to exist for the first time
|
||||
|
||||
`souveraine-sensord` has been `enabled` and **dead from every boot** (its unit
|
||||
hung off `graphical-session.target`, which nothing on this device starts —
|
||||
fixed 2026-07-27). The forensic trail proves the consequence: 2093 wake, 138
|
||||
transition, 121 decision, 29 error, and **not one sensor entry**. So the
|
||||
device state machine — and through doctrine §13, the agent — has never had
|
||||
sensor evidence at all.
|
||||
|
||||
Turning it on is therefore not "restoring" a stream. It is opening one.
|
||||
|
||||
### What the current shape gets right, apparently by accident
|
||||
|
||||
`sensord` reports **edges, not levels** (`de3a332`, "sensord: report edges, not
|
||||
every sample"):
|
||||
|
||||
- light → `{"changing": bool}`, never lux
|
||||
- accel → `{"moving": bool}`, derived from iio-sensor-proxy *orientation*
|
||||
changing, not from raw acceleration
|
||||
- proximity → near/far, debounced
|
||||
|
||||
That is close to the minimum an inference-first design would have chosen. The
|
||||
agent learns *that* something changed, not the waveform. Accel in particular
|
||||
is orientation-only, which is the difference between "the phone was picked up"
|
||||
and the 200 Hz stream AOSP had to cap.
|
||||
|
||||
**This should be written down as a property to preserve, not left as a
|
||||
side-effect of an unrelated commit.** Nothing currently stops a future change
|
||||
from passing lux through "because the machine needs it".
|
||||
|
||||
### Which is exactly what auto-brightness proposes to do
|
||||
|
||||
`DEVICE-STATE-MACHINE.md` §12 (auto-brightness) requires lux to enter as
|
||||
`sensor_input` so brightness can leave as an `Action`. That converts light
|
||||
from a boolean edge into a **continuous level**, and P1 says that is a tier
|
||||
change requiring justification, not an implementation detail.
|
||||
|
||||
Ambient light over time is the sleeper in this set. Individually it looks like
|
||||
the most innocent value on the device; as a series with timestamps it carries
|
||||
sleep and wake times, indoor/outdoor transitions, commute shape, and whether
|
||||
the house is occupied. Combined with proximity and orientation edges it is a
|
||||
timeline of a day — P1's "intersection attack" line, verbatim.
|
||||
|
||||
**The decision this task owes:** lux may be needed by the *machine* without
|
||||
being readable by the *agent*. Those are different consumers and the code does
|
||||
not currently distinguish them — `sensor_evidence` is on the snapshot and
|
||||
doctrine §13 makes snapshots agent-readable. Splitting "what `tick()` computes
|
||||
on" from "what `describe`/snapshot exposes" is the concrete work.
|
||||
|
||||
---
|
||||
|
||||
## 2. Grip is the sharpest case on the device
|
||||
|
||||
`elmyra_raw` is **six strain gauges at 100 Hz** (libssc patched to take the
|
||||
fastest advertised rate, TASK-13). Against P1 this is not a near-miss of the
|
||||
AOSP precedent — it is the precedent:
|
||||
|
||||
- **Keystrokes.** Every tap flexes the chassis. A 100 Hz six-channel strain
|
||||
array on the frame is a typing side-channel, which is the literal thing the
|
||||
`HIGH_SAMPLING_RATE_SENSORS` permission was retrofitted for.
|
||||
- **Identity.** Where and how hard a person holds a phone is a biometric.
|
||||
Google's own factory calibration (`edgesense_roller_cal`) exists because the
|
||||
gauges differ per unit and per grip — that sensitivity is the feature and the
|
||||
leak.
|
||||
- **Health.** Hand tremor is in that band.
|
||||
|
||||
TASK-13 has been, correctly, a bring-up task. It contains **zero tier
|
||||
analysis**, and its own producer is the leaky shape: `blueline-edge-sense`
|
||||
opens `elmyra_raw` and decodes six floats per sample **into AP userspace at
|
||||
100 Hz**, which is the highest-inference stream we have ever run.
|
||||
|
||||
### The architecture that makes it work is also the architecture that fixes it
|
||||
|
||||
This is the part worth not missing. TASK-36 established that squeeze cannot be
|
||||
configured from the AP at all: the AFE control surface
|
||||
(`ashConfigureElmyraFilters`) is reachable only from inside a CHRE nanoapp, and
|
||||
`elmyra.so` is that nanoapp. It consumes the raw gauges **on the SLPI** and
|
||||
emits a gesture.
|
||||
|
||||
So the correct implementation is also the private one:
|
||||
|
||||
| | raw stream | what crosses to the AP |
|
||||
|---|---|---|
|
||||
| `blueline-edge-sense` (today, diagnostic) | 100 Hz × 6 channels, in AP userspace | everything |
|
||||
| `elmyra.so` nanoapp (TASK-36) | stays on the SLPI | "a squeeze happened" |
|
||||
|
||||
That is the tiering argument made in hardware. **The rule this task should
|
||||
set: the raw `elmyra_raw` stream is a bring-up instrument, not a product
|
||||
surface.** `blueline-edge-sense` keeps existing as a diagnostic, gated and
|
||||
not running by default; the shipping path is the nanoapp's gesture event.
|
||||
|
||||
Doing it the other way — shipping the raw reader because it works sooner —
|
||||
would be P1's "gap, then a patch" repeated knowingly.
|
||||
|
||||
---
|
||||
|
||||
## 3. The dial enumerates capabilities, and enumeration is not gated
|
||||
|
||||
`TASK-31` already says the dial "does not appear over a locked screen with
|
||||
anything personal on it". That governs **painting**. It does not govern the
|
||||
IPC, and the IPC is the agent-facing surface.
|
||||
|
||||
`modules/souveraine/dial/DialHost.qml` today:
|
||||
|
||||
```qml
|
||||
IpcHandler {
|
||||
target: "dial"
|
||||
function open(): void { scope.dialOpen = true; ... }
|
||||
function close(): void { ... }
|
||||
function toggle(): void { ... }
|
||||
function entries(): string { /* label, icon, enabled, reason for every entry */ }
|
||||
}
|
||||
```
|
||||
|
||||
None of the four checks lock state, and `GlobalShortcut { name: "dialToggle" }`
|
||||
does not either. Two distinct problems:
|
||||
|
||||
- **`entries()` is reconnaissance without exercise.** P3 says capability *use*
|
||||
is visible, not just the grant — but enumeration is neither a grant nor a
|
||||
use, so it is invisible. The returned `reason` strings are designed to be
|
||||
explanatory ("no focused window to close"), which makes the refusal itself an
|
||||
information channel: it answers "is an app open right now" to any caller, at
|
||||
any lock state, leaving no trace.
|
||||
- **The contents are the leak, not the ring.** Today's entries are generic
|
||||
(lock, screenshot, kill window, health, agent, keyboard). TASK-31's whole
|
||||
design is that entries come from the verb tables (TASK-30) — at which point
|
||||
the dial's contents become "every mutating verb currently permitted", which
|
||||
is precisely a capability map, and a per-contact or per-app entry would carry
|
||||
personal data into the ring.
|
||||
|
||||
**The decision this task owes:** `entries()` must answer at the caller's tier,
|
||||
not the device's — an ambient caller sees ambient verbs. That has to be settled
|
||||
*before* TASK-30 feeds the dial, because afterwards it is a filter retrofitted
|
||||
onto a list, which is the shape P1 warns about.
|
||||
|
||||
---
|
||||
|
||||
## Acceptance
|
||||
|
||||
- The edges-not-levels property of `sensord` is documented as a requirement
|
||||
with a rationale, so a later change has to argue with it.
|
||||
- Lux reaches the state machine for auto-brightness **without** widening what
|
||||
the agent can read, or the widening is explicitly justified and recorded.
|
||||
- `elmyra_raw` is designated a bring-up instrument; the shipping squeeze path
|
||||
is the nanoapp gesture (TASK-36), and `blueline-edge-sense` does not run by
|
||||
default.
|
||||
- `dial entries()` and `dial open()` answer at the caller's tier, and the
|
||||
refusal `reason` strings are checked for what they disclose.
|
||||
- Each of these is justified in writing against P1, per its own "Application"
|
||||
clause — "looks innocent" is not a defense.
|
||||
|
||||
## Connects to
|
||||
|
||||
`SECURITY-AUDIT.md` P1/P2/P3, `TRUST-BOUNDARY-MATRIX.md`,
|
||||
`SESSION-AUTHORITY-DOCTRINE.md` §9 (evidence not fact) and §13 (agent-readable
|
||||
context), `DEVICE-STATE-MACHINE.md` §4 and §12, TASK-13 (grip), TASK-36 (the
|
||||
nanoapp that makes the tiering physical), TASK-30 (verb tables — the thing that
|
||||
will feed the dial), TASK-31 (the dial).
|
||||
|
|
@ -18,7 +18,7 @@ plus open threads from the 2026-07-17 session.
|
|||
| 8 | [Device state manager / power profiles](08-device-state-manager.md) | actuating 07-25 | clock + actuators; lock-before-blank is an invariant and hypridle's listeners are deleted; (b) charge real, (c)(d) open, **(e) lease still missing**, **(f) `sensors_degraded` reaches no surface**, **(g) the confidence gates need a decision before code** |
|
||||
| 9 | [Suspend-resume FTS calibration race](09-suspend-resume-fts.md) | interim-fix | kernel-side; cold-boot only |
|
||||
| 12 | [Face auth as a capability factor (Gaze reference)](12-gaze-reference-face-auth.md) | open | per-target: phone needs front-cam bring-up |
|
||||
| 13 | [Active Edge (squeeze) as a sensor input](13-active-edge-squeeze.md) | open, wanted | rail is UP and held from boot (07-26); step 2 now blocked on TASK-34 (SLPI doorbell) |
|
||||
| 13 | [Active Edge (squeeze) as a sensor input](13-active-edge-squeeze.md) | open, wanted | rail is a DT gpio-hog now (07-27); NOT blocked on 34; real path is TASK-36, and the raw stream needs TASK-40 first |
|
||||
| 14 | [Overview/app grid + Auxo multitasking](14-overview-appgrid.md) | in progress | shell-side; Home path + app cards |
|
||||
| 15 | [Idle coordinator: freeze, doze, scheduled wakeups](15-idle-coordinator.md) | blocked | freezing `app.slice` would freeze sessiond+shell+secrets; needs slice separation first (measured 07-25) |
|
||||
| 16 | [culver: usable messenger + contacts as Personal-class store](16-culver-messenger-contacts.md) | in progress | A/B/D landed; C contact card next; F is the folded-in TASK-01 |
|
||||
|
|
@ -37,8 +37,13 @@ plus open threads from the 2026-07-17 session.
|
|||
| 31 | [The radial dial](31-radial-dial.md) | open | component before contents; entries come from the verb tables, not a list in QML |
|
||||
| 32 | [The pill and the keyboard, as owned apps](32-pill-and-osk-as-apps.md) | open | both erroneous daily; neither has an owner or a shipping story |
|
||||
| 33 | [Battery and charging belong to the device state machine](33-battery-as-device-state.md) | open | last raw feed going straight to the glass; the charge ceiling is writable today |
|
||||
| 34 | [SLPI bring-up sequencing regression](34-slpi-bringup-sequencing.md) | open | old sequencing error; doorbell dies on SSR and stays dead; blocks TASK-13 step 2 |
|
||||
| 34 | [SLPI bring-up sequencing regression](34-slpi-bringup-sequencing.md) | **needs re-diagnosis 07-27** | doorbell is ACTIVE and sensors work (live lux measured); its `/sys/bus/iio/devices` test is not valid — SSC sensors never appear there |
|
||||
| 35 | [sessiond answers nothing: handler threads park forever](35-sessiond-handler-deadlock.md) | **open, live** | 347 threads in futex_wait, 691/1024 fds; accept loop fine, no request ever answered |
|
||||
| 36 | [CHRE nanoapp host for the SLPI](36-chre-nanoapp-host.md) | open | chrecd already runs CHRE with zero nanoapps; method table recovered 07-27, three methods to add |
|
||||
| 37 | ["Back" as a first-class verb](37-navigation-back-verb.md) | open | our Gestures.qml is already the compositor half; `can_go_back` is the dial's enabled/reason |
|
||||
| 38 | [Pill swipe-to-max swaps the keyboard](38-pill-swipe-osk-swap.md) | open | micro; the ONLY route to a terminal keyboard since stevia dropped its layout |
|
||||
| 39 | [Audio levels as tracked state, and sound roles](39-audio-levels-as-state.md) | open | check WirePlumber restores first; roles before a number |
|
||||
| 40 | [Inference tiering for the sensor surfaces](40-inference-tiering-sensors.md) | **open, gating** | P1 applied to sensord/grip/dial; blocks TASK-13's raw stream and gates TASK-31's IPC |
|
||||
| — | [Unify the shell trees](unify-shell-trees-laptop-phone.md) | open | ~900-file `ii` drift; blocks durable shell fixes reaching the phone |
|
||||
|
||||
Archived (see `archive/`): 05 crash reporter — done 2026-07-21,
|
||||
|
|
|
|||
Loading…
Reference in a new issue