diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 55dc231..aff9489 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -66,18 +66,26 @@ marked **DEFERRED** are ones the agent chose not to decide alone. pieces and I5's Android integration are all done; next is giving iris its own frame-timing report so item 3 below can be decided by a number. - **DEFERRED — whether to commit to iris over Masonry for `ai-app`.** - Updated 2026-09-05 with what's now known: iris's Android integration is - built and confirmed working on a real device (real server, real - scrolling, real touch-drag pan, tap-by-name accessibility — RUST.md's I5 - box), while Masonry's own touch-scroll on Android was already found - entirely absent (E2). What's still missing on **both** sides is a - render-time number — not because iris doesn't work, but because - `dumpsys gfxinfo` cannot see a `SurfaceView`'s GPU-drawn frames at all, - so the `transcript-bench.sh`-style comparison this recommendation wanted - produced a real number for Compose (8.96% janky, 99th percentile 150ms, - same emulator/session) and none at all for iris. The choice in front of - Iris: decide now on the structural-plus-functional case already made - (iris works end-to-end where Masonry's scroll gesture doesn't exist at - all on Android), or wait for iris to grow its own frame-timing - instrumentation first so the comparison can be a number rather than a - qualitative one. RUST.md's "Recommendation" item 3 has the full account. + Updated 2026-09-05 (later the same day) with what's now known: iris has + its own frame-timing report now (`FrameReport`) and a real number from + it, captured from a genuine on-device touch-drag — + `frames=34 janky%=61.76 p50=26.5ms p90=48.0ms p99=98.1ms worst=98.1ms` + — plus a confirmed on-device long-press-then-drag-to-select (logcat and + a screenshot of the highlighted selection). It is **not yet the clean, + comparable number** the recommendation wants: gestures against this + checkout's `EMU_GPU=software` emulator intermittently delivered zero + touch input during this session, reproducibly, for a reason named but + not yet confirmed (the emulator's own software rasterisation measured + at ~78% of a CPU core continuously — a plausible source of input + backlog, not yet isolated with a sampler running during a failing + gesture). The Compose figure quoted for comparison (8.96% janky, 99th + percentile 150ms) is the same one already recorded earlier 2026-09-05, + not re-taken this pass, and against a different sandbox session's + content — so the two numbers share configuration, not identical data. + The choice in front of Iris, updated: decide now on the + structural-plus-functional case already made (iris works end-to-end + where Masonry's scroll gesture doesn't exist at all on Android, plus a + real if narrowly-scoped frame-timing number), or wait for the + touch-delivery investigation above so the comparison can be the single + clean 24-swipe loop rather than a number gathered around an unresolved + rig flakiness. RUST.md's "Recommendation" item 3 has the full account. diff --git a/docs/IRIS.md b/docs/IRIS.md index 445bc96..70398ed 100644 --- a/docs/IRIS.md +++ b/docs/IRIS.md @@ -8,6 +8,49 @@ capability that moved. Small and trivial changes do not go here. An entry gives the date, what changed, why, and a short before/after where it helps judge the change without the session that made it. Newest first. +## 2026-09-05 (later the same day): `iris_core::FrameReport` (RUST.md's I5 box) + +New public type, `iris_core::FrameReport` (re-exported from `iris_core`'s +`render` module alongside `FrameStats` and `JANK_THRESHOLD`). Why: `dumpsys +gfxinfo` cannot see a `SurfaceView`'s own GPU-drawn frames at all, so a +`wgpu`-rendered iris screen had no way to ask "was this smooth" the way +Compose's own in-app render report already can -- item 3 of RUST.md's +recommendation was stuck on a one-sided number for exactly this reason. + +`FrameReport::record(elapsed: Duration)` is called once per frame (wired +into `android/view.rs`'s `render()`, wrapping the same span from redraw +start to after `queue.submit`+`present()` that Compose's report and +`gfxinfo` both count) and writes into a fixed 4096-entry ring -- no +allocation on the hot path. `FrameReport::report() -> Option` +gives total frames, janky % (over `JANK_THRESHOLD`, the same 16.7ms 60Hz +budget `gfxinfo` uses), P50/P90/P99 and the worst; `None` if nothing has +been recorded since the last `reset()`, not a zeroed report that would +read as a real measurement. `FrameStats`'s `Display` line says plainly +that it measures up to `present()` being called, not GPU/compositor +completion, since wgpu's `present()` isn't fenced against either. + +`AndroidUiState` gained a `pub frame_report: FrameReport` field -- +anything with `HasAndroidUiState` can now read or reset it. Before this, +there was no way to ask iris's own render path how long a frame took at +all, on any backend. + +Before/after, for a caller that already has `ui_state: &AndroidUiState`: + +```rust +// before: no such question could be asked +// after: +match ui_state.frame_report.report() { + Some(stats) => log::info!("iris frame report: {stats}"), + None => log::info!("iris frame report: no frames recorded yet"), +} +ui_state.frame_report.reset(); // via android_state_mut() +``` + +`iris-android-app`'s transcript screen exposes this as two named, +tappable controls ("Frame report", "Reset frame report") rather than +requiring a caller to wire its own UI -- see `transcript_client.rs`'s +`frame_report_controls`. + ## 2026-09-05: `Tasks::redraw_handle` (RUST.md's I5 Android integration) New public method on `iris::task::Tasks`, `redraw_handle(&self) -> diff --git a/docs/IRIS_TODO.md b/docs/IRIS_TODO.md index 24fddb2..2cb008e 100644 --- a/docs/IRIS_TODO.md +++ b/docs/IRIS_TODO.md @@ -186,25 +186,52 @@ order and what "done" looks like. Tick and date them in place. requirement, fixed by routing through `View::post_delayed` — see `IRIS.md`'s `Tasks::redraw_handle` entry). See RUST.md's I5 box, "The Android integration, done 2026-09-05" for the full account. - - [ ] **A render-time number for iris, comparable to Compose's - `transcript-bench.sh` report.** `dumpsys gfxinfo` cannot see a - `SurfaceView`'s own GPU-drawn frames at all (confirmed: 0 frames - reported across a gesture loop that visibly scrolled), and a - `dumpsys SurfaceFlinger --latency` fallback returned no per-frame - history either on this Android version's BLAST compositor. What's - needed is frame-timing instrumentation inside iris itself — a report - the way `UiRenderState::take_counters`/`AccessTree::take_rebuilds` - already expose counters, extended to timing. This is the one number - RUST.md's recommendation (item 3) is still waiting on. - - [ ] **Long-press-then-drag-to-select was not independently driven - on-device.** `ui-trace`'s two gesture primitives (`tap`, `swipe X1 Y1 - X2 Y2 MS`) cannot produce "hold stationary for `LONG_PRESS`, then drag - without lifting" — `swipe` interpolates motion across its whole - duration from the start. Needs either a new `ui-trace` action (a - genuine hold-then-drag primitive) or raw multi-step `MotionEvent` - injection. `DragArbiter`'s own unit tests already cover this exact - sequence against a synthetic clock (`iris/src/sense.rs`), which is why - this is "not independently driven on-device" rather than "unverified." + - [x] **A render-time number for iris, comparable to Compose's + `transcript-bench.sh` report — instrumentation done and a real number + obtained, 2026-09-05 (later the same day); the clean comparable loop + is not.** `iris_core::FrameReport` (`iris/core/src/render/ + frame_report.rs`, `IRIS.md`'s new entry) times every frame from + `render()`'s redraw start to after `queue.submit`+`present()`, exposed + as two named on-screen controls ("Frame report", "Reset frame + report"). Driven against a real on-device touch-drag it read + `frames=34 janky%=61.76 p50=26.5ms p90=48.0ms p99=98.1ms + worst=98.1ms` — real, not inferred, but accumulated across several + gestures rather than one clean 24-swipe loop, because of the new + finding below. See RUST.md's I5 box, "Update, 2026-09-05, later the + same day" for the full account. + - [ ] **New, 2026-09-05: intermittent touch delivery to iris's + `SurfaceView` under this checkout's `EMU_GPU=software` emulator.** + The same swipe coordinates, confirmed (by scanning a screenshot + column for the first non-black pixel) to sit over real row text, + sometimes produced 30+ real frames and a screenshot diff and + sometimes produced zero of either, across otherwise-identical + `ui-trace` invocations. Not the already-understood "already at that + scroll edge" case (reproduced with content confirmed taller than the + viewport, in both directions). Leading candidate, not yet confirmed: + this checkout's emulator was independently observed at ~78% of one + CPU core, continuously, while idle on-screen — SwiftShader's software + rasterisation is CPU-bound by design, and a synthetic touch competing + with that load for delivery is plausible but unmeasured *during* a + failing gesture (the standing rule against diagnosing from + after-the-fact measurements applies here). Needs a sampler (load, + `dumpsys input`, a `-i 0` `ui-trace` capture) running while a failing + gesture is driven, and ideally a comparison under `-gpu host` (real + Vulkan) to see whether it is specific to software rendering. This is + what blocks the clean, comparable 24-swipe loop above. + - [x] **Long-press-then-drag-to-select — confirmed on-device, 2026-09-05 + (later the same day).** `ui-trace` gained a `holddrag X1 Y1 X2 Y2 + HOLD_MS MOVE_MS` action (`emulator-tools`, additive, extends the same + `MotionEvent`/`injectInputEvent` mechanism `swipe` already used): + press, hold past `LONG_PRESS`, move, release, as one continuous touch. + Driven against a real row (`holddrag 300 1850 300 2050 600 300`) it + produced `iris selection: begin at row ...` then a sequence of + `iris selection: extend to row ...` log lines + (`transcript-ui/src/selection.rs`, a new small `log` dependency since + selection has no accessibility label of its own yet — see the next + item), and a screenshot taken right after shows the expected + highlighted selection spanning multiple rows. `DragArbiter`'s own + unit tests already covered this sequence against a synthetic clock; + this is the first time it has been driven by a real device touch. - [x] **Touch-drag panning over a row's own rendered text — done, 2026-09-05.** `row.rs` used to register `CursorSense::click_or_drag()` on each row's `TextEdit` for cross-row selection; `TextEdit::draw`'s diff --git a/docs/RUST.md b/docs/RUST.md index 91fde98..6d26284 100644 --- a/docs/RUST.md +++ b/docs/RUST.md @@ -36,23 +36,35 @@ session spending an afternoon on them again. ## Where things stand (2026-09-05) -- **I5's Android integration is done and measured, 2026-09-05 (still ticked - `[~]`, not `[x]` -- see I5's own box for exactly why).** The transcript - screen runs on-device against a real `ai-server`, with real scrolling, - real touch-drag panning and tap-by-name accessibility all confirmed by - screenshot/log evidence on this checkout's emulator. What the - recommendation still lacks is a render-time number for iris comparable - to Compose's `transcript-bench.sh` report -- not because the screen - doesn't work, but because `dumpsys gfxinfo` cannot see a `SurfaceView`'s - own GPU-drawn frames at all, and iris has no frame-timing - instrumentation of its own to ask instead. Two real, previously-unknown - bugs were found and fixed getting here (a missing `INTERNET` permission, - and a background-thread redraw request that crashed the process via a - `Looper` requirement neither this box nor `Tasks::redraw_handle`'s - design had anticipated) -- both in I5's own box, both in `IRIS.md`. - Next: give iris a render-time report of its own, the one piece left - before the iris-vs-Masonry recommendation can be decided by a number - rather than by structure alone. +- **iris now has its own frame-timing report and a confirmed on-device + long-press-drag, 2026-09-05, later the same day (I5's box still `[~]`, + not `[x]` -- see I5's own box for exactly why).** `iris_core::FrameReport` + (new) times every frame from `render()`'s redraw start to after + `queue.submit`+`present()`, exposed as two named on-screen controls, and + a new `ui-trace holddrag` action (in `emulator-tools`) can finally + produce a real hold-then-drag touch sequence. Both were driven for + real: long-press-then-drag-to-select is confirmed on-device (logcat plus + a screenshot of the highlighted selection), and `FrameReport` captured a + real number from a real touch-drag (`frames=34 janky%=61.76 p50=26.5ms + p90=48.0ms p99=98.1ms worst=98.1ms`). **What's still missing**: a clean, + single 24-swipe loop comparable to Compose's own number -- gestures + against this checkout's `EMU_GPU=software` emulator intermittently + delivered zero touch input during this pass, for a reason named but not + yet confirmed (candidate: the emulator's own software rasterisation, + measured at ~78% of a CPU core continuously, starving synthetic touch + delivery under load). Next: a sampler running *during* a failing gesture + to confirm or rule out that candidate, then the clean comparable loop. + I5's own box, "Update, 2026-09-05, later the same day" has the full + account. +- **I5's Android integration is done and measured, 2026-09-05.** The + transcript screen runs on-device against a real `ai-server`, with real + scrolling, real touch-drag panning and tap-by-name accessibility all + confirmed by screenshot/log evidence on this checkout's emulator. Two + real, previously-unknown bugs were found and fixed getting here (a + missing `INTERNET` permission, and a background-thread redraw request + that crashed the process via a `Looper` requirement neither this box nor + `Tasks::redraw_handle`'s design had anticipated) -- both in I5's own box, + both in `IRIS.md`. - **Design choices for the two pieces before this are summarised in `DECISIONS.md`** at the repo root, which is the file Iris reads for choices made without her. @@ -699,12 +711,35 @@ light" has a knob inside the same stack. programmatically (I3's benchmark plus I5's on-device screenshot evidence) — three structural points and one functional one in iris's favour, still with no opposing *or* supporting render-time measurement - on either side. **What Iris needs to weigh this**: whether "iris works - and Masonry's Android scroll path is absent entirely" is enough to - decide without a number, or whether the frame-timing work above is - worth doing first — a product/tradeoff call, not a technical one, so it - is left to her rather than decided here (DECISIONS.md's DEFERRED - item). + on either side. + + **Update, 2026-09-05, later the same day: iris now has a render-time + report of its own, and a real number from it, but not yet the clean + comparison item 3 needs.** `iris_core::FrameReport` (new, + `iris/core/src/render/frame_report.rs`) is exactly the follow-on work + named above — a per-frame wall-time ring exposed as two named on-screen + controls, unit tested (6 tests over the ring/percentile math). Driven + for real against a real touch-drag on this checkout's emulator, it + read `frames=34 janky%=61.76 p50=26.5ms p90=48.0ms p99=98.1ms + worst=98.1ms` — a genuine measurement through iris's own render path, + not inferred. **It is not yet the comparable number**, for a newly + found and separately named reason (I5's own box, "Update, 2026-09-05, + later the same day"): gestures against this checkout's + `EMU_GPU=software` emulator intermittently delivered zero touch input + during this pass — reproducible, but not yet root-caused past one + candidate (the emulator's own software rasterisation measured at ~78% + of a CPU core continuously, a plausible source of input backlog, not + yet confirmed with a sampler running during a failing gesture). So + item 3 still cannot be closed by a clean number, now for a narrower and + more tractable reason than before: the instrumentation exists and + works, and what remains is making the emulator rig deliver touch input + reliably enough to run the comparable loop. **What Iris needs to + weigh, updated**: whether "iris works, Masonry's Android scroll path is + absent entirely, and iris's own frame-timing report is real and + working" is enough to decide without the final clean number, or + whether to wait for the touch-delivery investigation above — still a + product/tradeoff call, left to her (`DECISIONS.md`'s DEFERRED item, + updated with this session's numbers). 4. Then the shell (E3), the desktop window (E4) and the packaging (E5), which do not depend on the choice. @@ -2309,17 +2344,23 @@ silently on real hardware. time it was hit (mid-session, after adding an unrelated temporary log line forced a dev rebuild) and cost real time to separate from the actual touch-dispatch question being chased at the time. -- [~] **I5 — the transcript screen in iris (2026-09-05). The widget-tree - half and the Android integration are both built and confirmed - working on-device (real server, real scrolling, real touch-drag - pan, tap-by-name); still `[~]` rather than `[x]` because the one - thing the recommendation actually wants -- a render-time number for - iris comparable to Compose's -- could not be produced on this pass, - for a reason named precisely rather than left vague: `dumpsys - gfxinfo` cannot see a `SurfaceView`'s own GPU-drawn frames at all, - and iris has no frame-timing instrumentation of its own yet to ask - instead. See "Measurements taken" and "What remains" near the end of - this box.** +- [~] **I5 — the transcript screen in iris (2026-09-05, updated later the + same day). The widget-tree half and the Android integration are + both built and confirmed working on-device (real server, real + scrolling, real touch-drag pan, tap-by-name), iris now has its own + frame-timing instrumentation (`FrameReport`) and produced a real, + measured number from a real on-device touch-drag, and long-press- + then-drag-to-select is now confirmed on-device too (both by logcat + and by a screenshot showing the highlighted selection); still `[~]` + rather than `[x]` because the frame-time number obtained is not the + clean, single 24-swipe loop comparable to Compose's -- gestures + against this checkout's `EMU_GPU=software` emulator intermittently + produced zero frames for reasons not yet isolated (candidate: the + emulator's own software rasterisation measured at ~78% of a CPU + core, continuously, which may be starving synthetic touch delivery + under load -- not yet confirmed with a sampler running during the + failing gesture). See "Update, 2026-09-05, later the same day" and + "What remains" near the end of this box.** **Where it lives.** `iris/transcript-ui/` (new workspace member, `[lib]`), the same shape as `iris/tabs-ui`: generic over `Rsc: @@ -2699,15 +2740,99 @@ silently on real hardware. a synthetic clock, which is why the mechanism is trusted enough to call "not independently driven on-device" rather than "unverified." + **Update, 2026-09-05, later the same day: (b) has a real iris number + now, and (c) is confirmed on-device.** Both needed new tooling built + this pass, recorded in `DECISIONS.md`: `iris_core::FrameReport` + (`iris/core/src/render/frame_report.rs`) times each frame from + `render()`'s redraw start to after `queue.submit`+`present()` into a + fixed 4096-entry ring, exposed as two named controls on the + transcript screen ("Frame report", "Reset frame report", + `iris/android-app/src/transcript_client.rs`) logged under this + crate's fixed `android_logger` tag; and `ui-trace` gained a + `holddrag X1 Y1 X2 Y2 HOLD_MS MOVE_MS` action in `emulator-tools` + (press, hold, move, release as one continuous touch via the same + `MotionEvent`/`injectInputEvent` mechanism `swipe` already used), + closing the exact gap named above. + + (b), continued: **a real iris number exists, but it is not the clean + 24-swipe `transcript-bench.sh`-equivalent loop this box originally + wanted, for a reason worth recording precisely.** Driving the + gesture loop against a freshly-restarted app repeatedly produced + **zero** frames recorded (both by `gfxinfo`, already known, and now + also by `FrameReport` itself) even though the coordinates were + confirmed on-screen to sit over real row text (measured by scanning + a screenshot column for the first non-black pixel, not guessed) -- + while the *same* coordinates driven a few commands later, or + combined into a slightly different sequence, sometimes produced 30+ + real frames and a genuine screenshot diff. This is not the earlier, + already-understood "already at that scroll edge" case (AGENTS.md's + own note) -- it reproduced with fresh content confirmed taller than + the viewport, in both scroll directions, inconsistently across + otherwise-identical commands. The one measured correlate: this + checkout's own `EMU_GPU=software` emulator was independently seen at + **~78% of one CPU core, continuously**, while idle on-screen (`ps + aux` mid-session) -- SwiftShader's software rasterisation is + CPU-bound by design (AGENTS.md's Vulkan-in-the-emulator section), so + a synthetic touch's delivery to the SurfaceView competing with that + load is the leading candidate, not yet confirmed with a sampler + running *during* the gesture (the standing rule against diagnosing + from measurements taken after the fact applies here and this pass + did not have time to build that sampler). Recorded as a new, + distinct, unresolved finding in `IRIS_TODO.md` rather than folded + into the already-closed "no `hold`-then-drag primitive" gap. + **The number obtained, honestly scoped**: tapping "Frame report" + immediately after a run that *did* produce real scrolling frames + (screenshots differ, confirmed by hash) read + `frames=34 janky%=61.76 p50=26.5ms p90=48.0ms p99=98.1ms + worst=98.1ms` -- real, measured wall-clock time through iris's own + render path from a real on-device touch-drag, not a synthetic + probe, but accumulated across several swipe gestures across + multiple `ui-trace record` invocations rather than one clean + 24-swipe loop, so it is **not directly comparable** to the Compose + figure below in scale, only in kind. Given the CPU contention + candidate above, a high jank percentage here is expected under + software rendering and should not be read as iris's number on real + hardware. The Compose figure quoted for reference + (**8.96% janky frames, 99th percentile 150ms, 212 frames rendered**) + is the same measurement this box already recorded on 2026-09-05 + earlier the same day, under the same `EMU_GPU=software` config on + this same checkout's emulator -- **not re-taken this pass** (the + session's time went to building the two rigs above and diagnosing + the flakiness instead), and against a *different* sandbox session + (40 messages, id `8920378e7167ebcd`) than this pass's own (120 + messages, id `c76b71d017a54589`), so the two numbers share + configuration but not identical content -- said plainly rather than + presented as a matched pair. + + (c), continued: **confirmed on-device, by both routes the task + asked for.** `ui-trace record --do "holddrag 300 1850 300 2050 600 + 300"` (a 600ms hold, comfortably past `DragArbiter`'s 500ms + `LONG_PRESS`, then a 300ms move) against a row's real text produced, + in order: `iris selection: begin at row 3165`, then a sequence of + `iris selection: extend to row ...` lines as the drag crossed row + boundaries -- logged from `transcript-ui/src/selection.rs`'s + `Selection::drag` (new `log` dependency, smallest addition since + selection has no accessibility label of its own yet, per + `IRIS_TODO.md`'s existing gap). A screenshot taken right after shows + the expected highlighted selection spanning multiple rows, + confirming the mechanism visually as well as in the log. This is + the first time `DragArbiter`'s pan-vs-select decision has been + driven by a *real* Android touch sequence rather than only its own + synthetic-clock unit tests. + **What remains, named rather than silently dropped (also in IRIS_TODO.md, dated 2026-09-05):** - - **A real per-app frame-time number for iris** -- (b) above. Needs - `iris` to grow its own render-report/frame-timing instrumentation - (what the Compose app's copy-button report already gives) before - any `dumpsys`-based comparison can go further than functional. - - **Long-press-then-drag-to-select, on-device** -- (c) above. Needs - a driving primitive this pass's tools do not have. + - **Intermittent touch delivery under `EMU_GPU=software` CPU load** + -- new finding above. Needs a sampler running *during* a failing + gesture (load, `dumpsys input`, a frame-by-frame `ui-trace` + capture at `-i 0`) rather than another guess after the fact, and + ideally a comparison against `-gpu host` (real Vulkan, but shared + with whichever GPU config a peer session's emulator already + holds) to see whether it is specific to software rendering. + - **A clean, single 24-swipe `transcript-bench.sh`-equivalent + iris number** -- blocked on the above; the number this pass got is + real but not that clean run. - **Row-level accessibility names** -- behaviour 6, I5's own writeup above. - **A tappable link and a code-span background chip** -- behaviour 2. @@ -2720,21 +2845,21 @@ silently on real hardware. own unit tests), not by a dedicated repro this pass. **Net for the recommendation.** Item 3 ("decide when the transcript - screen exists in both, from the measurements") still cannot be - decided by a render-time number on either side -- E2 could not - produce one for Masonry (no working touch-scroll to measure), and - this pass could not produce one for iris either, now for a different - and more fixable reason: `iris` itself has no frame-timing - instrumentation yet, not that the screen doesn't work. What *can* be - said, updating E2's own conclusion further: iris now has a real, - working Android integration -- a real server, a real scrolling - transcript, real touch-drag panning, tap-by-name accessibility, all - confirmed on-device -- plus the two structural points E2 already - found Masonry unable to reach at all (cross-row selection, true - per-span inline rich text). Whether iris's *smoothness* matches or - beats Compose's is the one question actually left for whoever picks - up "add frame-timing instrumentation to iris" next; DECISIONS.md's - DEFERRED item is updated with exactly this gap. + screen exists in both, from the measurements") now has a real number + on the iris side for the first time -- `FrameReport` works, is unit + tested (6 tests over the ring/percentile math), and captured a real + on-device touch-drag's timing -- but that number is scoped narrowly + (accumulated over several gestures, not one comparable loop) because + of the intermittent-touch-delivery finding above, so it still cannot + be read against Compose's 8.96%/150ms figure as a clean comparison. + What *can* be said, updating the account further: iris's Android + integration, its frame-timing instrumentation, and its long-press + selection have all now been exercised by real on-device touch input + end to end (not only unit tests), on top of the structural points + E2 already found Masonry unable to reach at all (cross-row + selection, true per-span inline rich text). `DECISIONS.md`'s + DEFERRED item is updated with this session's numbers and the + touch-delivery caveat rather than a decision made here. ## For the next agent