# Ticket: Graph follow newest across all zoom levels

Status: complete; A/B real-signal target proof and operator acceptance passed
Type: ticket
Updated: 2026-07-26
Next Action: none
Parent: work/wp/completed/wp-correct-hpt-graph-rolling-cache-refresh.md

## Problem

Both controllers publish new persisted records into their stable SDRAM chart
cache, but the open Graph viewport does not remain attached to the newest
record. On Controller B, a live capture showed chart publication sequence 74
fully rendered while the one-hour viewport high remained at HPT `301829400`;
the newest chart record was `301830180`. Controller A showed the same viewport
high with a newest chart record of `301830120`.

The HMI inferred follow state by allowing only a one-pixel difference between
the viewport high and the previous newest record. Grid-aligned planning rounded
the one- and three-hour view to a half hour, and wider views to an hour. Once
that rounded edge fell more than one pixel behind, subsequent publications
redrew data without advancing the viewport.

The last printed X-axis label is also the internal 600-pixel grid line. The
720-pixel viewport edge had no time label, so at one-hour zoom the latest
visible label was intentionally ten minutes older than the actual edge. That
made a healthy cache appear stale.

Operator review then exposed a separate timer-lifecycle defect that the RAM
review-command qualification had bypassed. Graph opens with repeating
`TIME_EVENT_TIMER` scheduling, but every real zoom/pan callback calls the
generic `refreshIdleTimer()`. That call restarts the same widget/timer ID as a
one-shot idle timer, so the Graph event handler stops polling
`gChartDataSequence`. Live captures after real operator zoom showed A at
published/rendered sequence `44 / 36` and B at `70 / 62`, with both attached
viewports four persisted records behind while logging continued normally.

## Expected Behavior

Opening Graph attaches its right edge to the newest persisted record. Every new
published record advances an attached viewport at every zoom level. Button
zoom preserves attachment. Pan Left or selecting a graph area deliberately
holds the inspected historical range. Pan Right eventually reaches the exact
newest record and reattaches. The right edge displays its actual timestamp.

## Acceptance Criteria

- [x] Follow-newest is explicit state, not inferred from grid or pixel proximity.
- [x] New record publication anchors an attached viewport exactly at the newest
  persisted timestamp.
- [x] Pan Left and graph-area selection disengage following; history remains
  stationary while new records arrive.
- [x] Pan Right reaches the exact newest record, re-enables following, and is
  then unavailable until another record arrives.
- [x] Button zoom in/out preserves follow state and exact newest anchoring.
- [x] The viewport's 720-pixel right edge has an exact time label in addition
  to the five internal grid labels.
- [x] A focused executable model passes for 1, 3, 6, 12, and 24 hour zooms.
- [x] Every repository `script/check-*.ps1` suite passes.
- [x] A clean isolated managed Debug build and production package pass.
- [x] Controller B is programmed first without format, HPT initialization, or
  media replacement; CID and abnormal `86 / 86 / 1` lane starts are preserved.
- [x] On B, an open attached Graph advances after a new record at every zoom
  after each zoom level is selected through the real GUI event/callback path.
- [x] Controller A receives the identical verified image and passes the same
  real-event all-zoom live advancement check.
- [x] Zoom, pan, and graph-area selection reset only the Graph software
  inactivity mark; they do not replace its repeating GUI update timer.
- [x] Automated regression coverage rejects Graph click paths that call the
  generic one-shot `refreshIdleTimer()` and distinguishes real GUI event
  qualification from direct action-command qualification.
- [x] Both controls are left on Graph with cache-load timing and exact image
  identity recorded for operator review.

## Verification

- `script/check-graph-follow-newest.ps1` statically checks the state contract
  and models publication, pan-away, and exact reattachment at all five zooms.
- Run every `script/check-*.ps1` suite.
- Run an isolated clean managed Debug build and verify/package the S-record.
- Capture baseline and post-program CID/service state from each control.
- Observe chart publication sequence, newest timestamp, viewport high, follow
  state, zoom, and cache timing before and after new persisted records.
- Exercise the same Graph task-button and graph-area event handlers used by an
  operator; direct calls to `performZoomPanButtonAction()` are insufficient.
- Record the hash-locked A/B result in a compact evidence artifact.

## Execution Plan

1. Preserve the live failure captures and Controller B's CID and abnormal
   `86 / 86 / 1` lane starts.
2. Keep the Graph repeating timer configured at screen entry; interaction
   handlers update only `returnToMainMarkTime`.
3. Add focused static/model checks for timer ownership and real GUI-event
   coverage.
4. Run focused checks, every repository `check-*.ps1`, and a clean isolated
   managed Debug build/package.
5. Program B first without format/reinitialization, capture CID/status/cache
   timing, and qualify all zoom levels using real GUI click events followed by
   a subsequent persisted minute record.
6. Program the identical image on A and repeat the same qualification.
7. Leave both controls attached to newest data at one-hour zoom for operator
   review and record exact hashes and measured refresh results.

Evidence:
`work/evidence/graph-follow-newest-correction-20260726.md` and
`work/evidence/graph-real-event-refresh-timer-correction-20260726.md`.

## Operator Acceptance

On 2026-07-26 the owner observed that the Graph advances while zooming in and
explicitly called the correction good. This closes the live-refresh behavior
change. Separate export workflow acceptance remains owned by its export/read
performance artifacts and is not implied by this ticket closure.
