# Proof audit, pass 1 — keyboard ownership

PR [#18338](https://git.cafe/pingdotgg/t3code/pull/18338) ([GitHub mirror](https://github.com/pingdotgg/t3code/pull/18338)). Read-only review of `/home/ubuntu/wt/pr-18338`, local branch `pr-18338`, supplied unpushed head `ca755a09748502222d0a2097fa59874fc1d95b5e`, using `git diff origin/main...HEAD`. Local `origin/main` is [354f6c86dd](https://git.cafe/pingdotgg/t3code/commit/354f6c86ddb0a431351e59fa38a5d5d16b1bb81f); merge base is [becf853def](https://git.cafe/pingdotgg/t3code/commit/becf853defb6127dbe4447860383777d69346b6f). Six changed files, +229/−21. Audit began 2026-10-27 02:12 UTC; 60-minute ceiling. No server, browser, tests, source edits, pushes, or comments were run. This is a proof plan, not a claim of observed behavior.

## Findings first

1. **Blocking proof gap: no current-head capture exists.** Every required row R1–R8 below is MISSING. These are keyboard-routing sequences: all need **recording**, with both the visible stop and composer content observable. Stills cannot prove ownership, close timing, or loading handoff. Existing added browser tests use a chat handle stand-in and a mocked guide query; they do not prove the production panel/sheet integration.
2. **The old SQLite seed is not admissible for this pass.** The supplied [seed script](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/39e24479211dcc2d/seed.py) directly replaces project/thread projections and guide rows and writes settings; its [README](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/e240cd8340126d61/README.md) explicitly describes that approach. Both were fetched and read, never executed. Use the fresh-server/app/RPC procedure below. The prior script also depends on a separate data.json and a historical guide head, so it is not a self-contained current fixture.
3. **A prepared guide cannot be uploaded with an existing public RPC.** Only `pullRequests.reviewGuide` (get) and `pullRequests.generateReviewGuide` (start a provider run) exist. A real fresh database can receive a guide through the generation RPC and its repository `put`; generation does not guarantee a count, so inspect the returned stops before recording. Exact zero/one/three-stop fixtures and a controlled pending-query transition require a labelled harness if the real generation/network flow cannot supply them. No direct SQL seeding is proposed.
4. **Sheet expectations must respect its modal state.** The narrow path uses a retained Sheet popup. `shouldRedirectInputToComposer` explicitly rejects input while a sheet is open/closing. Do not claim Shift+J types into the composer behind an open sheet, or fabricate a chat click through its backdrop. R2 proves J/K stepping there and return to chat after dismissal. R1/R3/R5 prove type-to-focus and chat handoff in inline layout. This is an existing guard, not a new defect established by this audit.
5. **Forge checks concern another revision.** GitCafe currently reports the older pushed head [ce1aa4035b](https://git.cafe/pingdotgg/t3code/commit/ce1aa4035b7512ccfa9fbb6e94ee840019b71121). Its successful checks and historical recordings are not evidence for the supplied local candidate. No code defect was established by this focused proof-planning audit; runtime behavior remains unverified.

## Render-path inventory and equivalence classes

This inventory covers every production caller of the changed components and every branch governing the changed routing seam. Unchanged header/menu/status presentation is explicitly collapsed, rather than making a new proof row for each unrelated PR action.

| Changed seam | All production callers / inputs | Branches and interactions to retain in the fixture space |
|---|---|---|
| `RightPanelTabs` → internal `RightPanelEmptyState` | `ChatRightPanel` returns inline tabs or tabs in `RightPanelSheet`; `PullRequestsPage` renders inline tabs directly. Empty launcher mounts only when `activeSurfaceId === null`, otherwise `children`. | `open` false/true/exit presence; inline normal/maximized versus sheet; surfaces empty/one/many and overflow; `layoutControls`; Electron inline titlebar versus web; resolved light/dark theme. Launcher maps all seven actions and advertises **only available** letters, lower+upper: Browser B, Terminal T, Files F, Diff D, Pull request P, Linked pull requests L, Device M. Availability is independently supplied for each action. All unavailable is an empty claim; mixed availability is the production web fixture. Browser profile count ≤1/>1 adds a profile menu. Focus on mount, pointer highlight, arrow cycling, Enter, action click, window capture letter handling, popup blocking, typing-context/modifier/composition/defaultPrevented guards. Tab activation, close/middle-close/context close, reorder, plus-menu letters are unchanged; use activation/close in R4. Tab labels/pending/audio/favicons/theme/status data do not change the marker. |
| `composerFocusRedirect.ts` | `useChatShortcuts` calls changed `shouldTypeToFocusComposer`; `usePasteToFocusComposer` and `timelineViewport` use its **unchanged** helpers. No React render path of its own. | Zero/one/multiple `[data-claimed-keys]` elements; any exact-case match wins globally. The guide advertises `jk`; launcher advertises both cases. Printable one-character key only; early exits for handled/composition/Ctrl/Meta/Alt, secret requests, editable or interactive event paths, floating layers. Chat additionally checks enabled, terminal/model-picker focus and command palette. Unclaimed letters type-to-focus. Paste, scrolling, and existing explicit keybinding precedence are unchanged. |
| `PullRequestDetailPanel` | `RightPanelSurfaceContent` for chat PR surfaces; `PullRequestsPage` for page PR detail. Chat passes `shortcutsEnabled = visible && activeSurfaceId === surface.id`; page compares active and rendered PR surface IDs. | Detail pending with no data → ghost; unavailable/error → no guide; detail ready → summary/guide/timeline/code. Guide setting off hides Guide and falls back to summary; unavailable Code falls back likewise. `initialTab`, page-store tab (`tabOnPage`) and later selections choose the tab; tabs are retained after first visit but reset per environment/reference. Guide `active` is now `shortcutsEnabled && tab === guide`, so active, inactive tab, hidden panel and exit-animation states matter. Thread/page context, nullable thread/draft target, back/close callbacks, title/workspace root, permissions and diff capabilities shape unchanged chrome/actions. Ask/finish/open-file callbacks can open a thread/review editor or switch to Code; those are interactive/focus guards, not new layout behavior. |
| `PullRequestGuideTab` | One production caller: retained Guide subtree in `PullRequestDetailPanel`; additional caller is the changed browser-test harness only. | Local engagement initially true; pointerdown/focusin inside `[data-chat-column]` → false; any other target → true; inactive→active resets true. These listeners exist **before** pending data resolves and clean up on unmount. `active && engaged` controls `GuideTour`. No guide + pending/null data → spinner; no guide + running → writing state; no guide + idle → empty/write state; current-head failure or query error changes detail/retry. A guide remains shown while running, stale, or failed: banner priority running > failure > stale; write permission controls Write/Rewrite/Retry; running disables it. `canComment`, `rangeComments`, pending comments, nullable ask/finish handlers change editor/action availability, not the claim predicate. `onTourShown` reports active non-null guide even before engagement. |
| `GuideTour` | One production caller: `PullRequestGuideTab`. | Stop lengths 0, 1, >1; claim only if active and length>1. Listener is active-gated even at 0/1, so one-stop behavior must be observed with the composer present. Position is clamped to first/middle/last; J/K clamp at ends, seen count updates on forward movement, scroll resets, rail closes. Guide container <30rem hides keycaps/file notes; <56rem uses collapsible stop list, ≥56rem shows sticky rail; ≥90rem widens layout and moves notes into an aside. Content width, not viewport alone, determines these branches. Stop absent → no-files message; nonempty summary, attention (five labels), excerpts, other files, notes, questions, diff loading/error/missing files, ask/finish availability add unchanged content. Current progress is keyed by environment+PR+guide head. Previous/Next/footer/rail selection, rail open/close, file expand/open, inline comment/ask input and finish review are existing interactions. New key acceptance matches `event.key` exactly (`j`/`k`) and no longer rejects Shift as a blanket rule. Editable target, composing, command palette, Ctrl/Meta/Alt, already-handled events still suppress stepping. |

Client/connection scope: web and Electron share these components; React Native mobile does not call them. The narrow web sheet is not the native mobile client. No provider adapter, contract, transport, server behavior, or local/remote/relay branch changes; one host/local web run is enough for routing. A desktop Browser-launcher check is optional because Browser is the only platform-dependent advertised action; all seven use the same claim construction. Explicit custom J/K command bindings retain their existing precedence and should be absent in the baseline fixture.

## Data and fresh-app setup

**Required start:** the capturer must start the isolated dev server with `T3CODE_DEV_SEED=0 vp run dev` against a genuinely fresh task-owned T3 home/database. This flag does not erase an existing database. If the worktree already has state, select another explicit isolated home with `T3CODE_DEV_SEED=0 vp run dev --home-dir <new-task-owned-home>`; do not delete or reuse the developer's live state. Read the actual ports from the dev-runner output. Do not set VITE_HTTP_URL/VITE_WS_URL. Do not migrate/copy the live database. Add the project and create a stopped thread through the app (or their actual orchestration RPCs), so both have normal event history. This audit did not start that server.

**Real-app path A (available without a new fixture endpoint):**

1. Add this checkout as a project in the fresh app. Connect the forge account as needed through the app, use the existing project repository identity, and link/open only PR [#18338](https://git.cafe/pingdotgg/t3code/pull/18338) from the thread's PR UI. This adds a local link; do not create, comment on, or change the PR. Origin is GitCafe, so use host `git.cafe`, repository `pingdotgg/t3code`, number `18338` consistently; do not seed a github.com key and then open git.cafe.
2. In this isolated environment's `/settings/source-control`, enable Review guides (`reviewGuidesEnabled`) and select an available authenticated guide provider/model (`reviewGuideModelSelection`). Set guide instructions to request at least two distinct titled stops with nonempty prose, and assign actual changed files to them. For example: “Use three titled stops: Keyboard ownership, Chat handoff, Release. Give each a short nonempty summary. Cover all changed files. Use only paths in this change.” These are fixture instructions, not code changes.
3. Open the Guide tab and choose Write guide. The equivalent authenticated RPC is method `pullRequests.generateReviewGuide`, payload `{ "projectId": "<ID returned by the app>", "host": "git.cafe", "repository": "pingdotgg/t3code", "number": 18338 }`. Use the app's typed RPC client/protocol; this is a method+payload description, not an invented raw WebSocket frame. The caller needs the orchestration-operate grant. The generated guide concerns the forge's PR head; it need not equal the locally served candidate head.
4. Concrete write path: `ws.ts:2643` → `PullRequestReviewGuideService.generate` → own-repository/settings/head checks → `write` → checkout/fetch real PR refs and `TextGeneration.generateReviewGuide` → `normalizeReviewGuide` → `PullRequestReviewGuideRepository.put`. That repository schema-encodes the guide and upserts `pull_request_review_guides(host, repository, number, guide_json)` in the **fresh isolated** statev2 database. Do not issue this SQL yourself. Generation uses a temporary checkout, not a guide written by a chat message. Existing `reviewGuidesEnabled` false or missing provider/forge auth will prevent this path.
5. Wait through the app's normal completion notifier/query, then read `pullRequests.reviewGuide` with the same payload. Require non-null `guide` and `guide.stops.length >= 2` before recording R1/R2/R4/R5/R8. Prefer 3 stops for first/middle/last. If generation returns <2, rewrite with the instructions and validate again; never label a one-stop clip proof of stepping. This process is provider-dependent, not deterministic. Record actual guide head, generatedAt and stop titles in the capture manifest. Do not publish auth material.
6. Navigate the thread at `/<environmentId>/<threadId>` using IDs returned by the app; open its PR panel and Guide. For R8 use `/pull-requests`, select the same project/environment and PR, then Guide. Page selection uses repository/number/selectedProjectId/selectedEnvironmentId/selectedHost search fields; selecting through the UI avoids hand-encoding router search types.

**Deterministic fallback B — label HARNESS, never “real fresh app”:**

There is no supported arbitrary-guide put RPC. If provider runs or exact query timing are unavailable, capture a temporary browser harness outside tracked source, mounting the production `useChatShortcuts` and `PullRequestGuideTab` with a visible composer and a `[data-chat-column]` transcript plus neutral panel chrome. Mock only `useReviewGuideWriter` at the existing test seam; keep a stable mounted tab while changing its query result, as the current `useChatShortcuts.browser.test.tsx` does. Return `canWrite:false`, `running:false`, `write: async () => {}`, and either pending `{ query:{isPending:true,error:null}, data:null }` or ready `{query:{isPending:false,error:null},data:{currentHeadSha:"fixture-head",run:null,guide}}`. A guide uses `{headSha:"fixture-head",generatedAt:"2026-10-27T00:00:00Z",modelSelection:{instanceId:"codex",model:"fixture-model"},stops:[...]}`. Each stop has title, nonempty summary, attention:null, excerpts:[], files:[], notes:[], questions:[]. Use three distinct titles and prose. Empty file arrays avoid an unrelated diff fetch. Slice that array to 1 or 0 for count controls. Use actual stop text and visible composer state in the recording, not just a key-event array. This proves the component seam, not the production RightPanelTabs, DetailPanel active gating or modal integration. It cannot replace real-app R1/R2/R4/R7/R8 proof.

R3's controlled **query pending → data arrival** can use this harness directly: mount pending, click/focus chat, then deliver the ready result without remounting. Real running-generation “Writing a review guide” is a different branch, although it also keeps the same engagement state; a real-app version can record that transition in addition. A real-app RPC transport gate that holds only the guide answer while the mounted tab shows pending is also acceptable if clearly documented; simply delaying the entire PR detail prevents the tab from mounting and does not reproduce the race.

For an integration harness that must exercise actual generation persistence, the existing `PullRequestReviewGuideService.test.ts:150` demonstrates injecting `TextGeneration.generateReviewGuide = Effect.succeed({stops: threeStops})` while keeping the real guide repository. A temporary server harness can use that service substitution and let the normal `pullRequests.generateReviewGuide` RPC write the database. It must retain the real project/service/RPC setup, satisfy repository identity and forge detail/fetch requirements (or explicitly label those as fakes), and wait for repository completion. This is a **server harness**, not an existing production seed command. The existing test itself uses an in-memory database and fake project/forge services; running it does not seed the dev app.

## Minimum capture matrix

All required cells below are **recording**; MISSING means no capture was supplied in pass 1. One recording may contain several labelled segments/rows. “Affected” includes a regression control on a changed predicate. Baseline: normal keyboard mappings, no custom plain J/K bindings; stopped thread with an enabled empty composer; same guide data on both comparison revisions. Use a brief event overlay or accompanying trace showing key/shift/Caps state and target alongside visible app behavior. A synthetic Caps event must be labelled synthetic; it is not proof of physical Caps Lock behavior.

| ID / named fixture | Data, layout and action sequence | Diff affected? | Minimum viewport × theme | Seeding / reachability | Kind | Status |
|---|---|---|---|---|---|---|
| R1 — inline guide owns keys, chat takes them, chrome takes them back | ≥2 stops, preferably 3, nonempty prose. From neutral guide prose click, J forward/K back without composer text. Click neutral `[data-chat-column]` transcript → j/k insert, stop unchanged. Separately focus an element in that column → same handoff. Click noninteractive panel chrome (e.g. blank tabbar) and prose → stepping resumes. Traverse first/middle/last and clamp at boundaries. Record the composer throughout. | Yes: global claim and engagement | 1440×1000 × dark, viewport >980; ordinary side panel | A; B is only supplementary component proof | recording | **MISSING — required** |
| R2 — retained narrow sheet | Same ≥2-stop guide; click prose/chrome and step both directions. Dismiss sheet, wait for popup closure, click chat and type j. Reopen and confirm guide stepping returns. Keep panel animations enabled. Do not click through the backdrop or expect uppercase input behind an open sheet. | Yes: distinct modal caller and active gating | 390×844 × light (real CSS viewport; hardware keyboard events) | A; real ChatRightPanel → RightPanelSheet required | recording | **MISSING — required** |
| R3 — chat engagement survives loading | Mounted Guide tab has `guide:null`, query pending. Click neutral chat transcript, then resolve to ≥2 stops **without remount**; j/k go to composer and guide stays on first stop. Repeat via focusin; contrast untouched pending→ready, which owns j/k. A no-guide generation-running→ready segment can supplement this. | Yes: listeners moved before loaded GuideTour | 1440×1000 × dark | B: labelled component harness with controlled query; A only if exact query answer can be gated, not whole detail response | recording | **MISSING — required** |
| R4 — inactive/closing/reopened guide | Begin engaged ≥2 stops. Switch Guide→Summary/Code; guide stops claiming. Return, then close the panel while engaged, covering the retained exit interval and settled state; reopen after a prior chat handoff and confirm guide owns again. For immediate close use a neutral event target and log claim absence/stop unchanged: a click into chat alone would mask broken visibility gating, and a focused close/toggle button can suppress type-to-focus independently. Include surface switch if available; inactive Guide tab must not steal keys. | Yes: `shortcutsEnabled && tab` and active reset | 1440×1000 × dark; sheet exit covered R2 | A, actual DetailPanel/RightPanelSurfaceContent required. Component active=false harness alone is insufficient | recording | **MISSING — required** |
| R5 — case and focused editor | ≥2 stops. Click neutral prose; physical Shift+J yields key `J`, inserts uppercase J, no stop change. Re-click prose (typing focused composer); Caps Lock+Shift+J yields key `j` with shift=true, steps, no composer insertion. Also show plain Caps Lock J (`J`) types, or explicitly note equivalent case path. Focus composer/other real editor and type j/k: text stays there, guide does not step. Reclaim guide between sequences. | Yes: case-sensitive claim and removed Shift guard | 1440×1000 × dark | A. If Caps Lock cannot be driven, label the dispatched key=j/shift=true segment synthetic and leave physical Caps verification unclaimed | recording | **MISSING — required** |
| R6 — exactly one stop | One titled prose stop, no running/error banner. Click prose with a noneditable target and type j then k (refocus prose between keys): input reaches composer, guide unchanged, no advertised jk. The composer must be enabled. | Yes: `stopCount > 1` boundary | 1440×1000 × dark | A only if generated guide is verified exactly 1; otherwise B labelled count-control harness | recording | **MISSING — required** |
| R7 — mixed-availability launcher, both letter cases | Open empty right panel (`activeSurfaceId:null`) after chat is already mounted; Files enabled, Browser disabled in web, other capabilities per app. With launcher/neutral target focused, f opens Files with no composer text; restore empty launcher, F does the same. Restore; unavailable b and unclaimed a reach composer (neutral target), and focused composer typing is not hijacked. Repeat lower/upper for other available letters if cheap; all share one construction. | Yes: renamed marker and both-case advertisement | 1440×1000 × dark; no Guide mounted | A; close surfaces/show panel to reveal launcher, no DB seed needed | recording | **MISSING — required** |
| R8 — Pull Requests page caller, expanded guide | Same PR/guide, no chat composer. Open Guide from Pull Requests page; enlarge/maximize actual guide container to ≥56rem so sticky rail is visible. J/K step, rail selection works, first/last controls are correct. Switch away/close/reopen; log marker absence and a neutral-target j no longer being prevented when page detail is inactive (there is no composer on this route). | Yes: second DetailPanel caller and active gate; rail visual is unchanged | 1920×1080 × light; ensure measured guide container ≥896px | A; `/pull-requests` → select same PR → Guide | recording | **MISSING — required** |

Minimum distinct viewport/theme cells: (1440×1000,dark,R1/R3/R4/R5/R6/R7), (390×844,light,R2), (1920×1080,light,R8). These are eight behavioral rows, not eight mandatory separate videos. Theme is not a routing branch, so no per-row light/dark cross-product is required. The light sheet and page clips plus dark inline clips cover both appearances without inventing visual-change proof. A few labelled reels can cover them. R1 must include a **before** segment on the unmodified `origin/main` comparison code (record its exact SHA) with the same ≥2-stop fixture: guide prose click + j is stolen into composer. Replaying R1's sequence after the fix provides the defect-to-fix comparison; the remaining rows need current-head recordings, with before segments where practical. Do not manufacture unrelated visual differences. Identify served source revision and guide metadata head separately.

## Additional visually distinct states, collapsed out of minimum proof

These are catalogued so an evidence collector does not mistake their absence for an unexamined code branch. They do not expand the required matrix because their presentation did not change and their key routing is represented above. If captured, each interactive/time-dependent row still needs **recording**, not a still.

| ID / fixture | Required data / branch and how to reach it | Effect of diff / relation | Kind if captured | Status |
|---|---|---|---|---|
| C1 — no guide, idle | `guide:null`, pending false, no run, no error; fresh app before Write guide; write permission toggles Write button | No new claim element; engagement exists but no tour yet; R3 covers later arrival | recording | CATALOGUED — no extra required capture |
| C2 — no guide, generating | `guide:null`, run Running or writer starting; real Write guide in A, provider completion controls duration | Engagement persists; R3's running→ready supplement is useful but distinct from query-pending spinner | recording | CATALOGUED — no extra required capture |
| C3 — no guide, failure/query error/read-only | Current-head Failed detail or query.error, canWrite true/false; provoke a failed generation in isolated A or B; Retry versus no action | Error text/buttons unchanged; editor/button focus guards unchanged | recording | CATALOGUED — no extra required capture |
| C4 — zero stops | Valid guide schema, `stops:[]`; B. Real generation for a nonempty PR normally appends Other files, so do not promise an exact-zero real seed | Same no-claim branch as R6; visibly distinct no-files body | recording | CATALOGUED — optional harness boundary control |
| C5 — loaded, stale banner | CurrentHeadSha differs from guide.headSha, no running/failure; B or a later genuine host push (do not mutate PR for this audit) | Active ≥2 still owns; banner presentation unchanged | recording | CATALOGUED — no extra required capture |
| C6 — loaded, rewriting banner | Existing guide plus run Running; Rewrite in isolated A; canWrite/running determines action | Same claim as R1 through refresh; visible spinner/time branch unchanged | recording | CATALOGUED — no extra required capture |
| C7 — loaded, failure banner | Existing guide, current-head Failed, not running; B or genuine failed rewrite in isolated A | Same claim as R1; failure beats stale warning, button depends on permission | recording | CATALOGUED — no extra required capture |
| C8 — rich stop / large container | Summary empty/nonempty; attention absent/present with any of 5 labels; excerpt/file/note/question arrays empty/nonempty; diff loading/error/missing/ready; pending comments and ask/finish null/present. A from actual generated content, or B for deterministic combinations | All are children of same active tour root. Narrow <30rem (R2), compact <56rem (R1), rail ≥56rem (R8); ≥90rem adds note aside and spacing. Long text/path wraps, file count 0/1/many, file expand, comment editor and ask/review dialog create unchanged layouts/typing guards. No full cross-product needed for a nonvisual routing fix | recording | CATALOGUED — rich-editor guard may be covered in R5; no extra visual captures required |
| C9 — other shell/launcher variants | Sheet width 761–980 versus ≤760; inline maximized; light/dark/system resolved colors; surfaces 0/1/many overflow; unavailable actions/zero available; browser profiles 0/1/>1; Electron titlebar + Browser enabled | Marker independent of theme, tab overflow, profiles and maximize. All-unavailable launcher generally needs harness (chat has available Files/Device); page caller renders a selected PR, not launcher. Electron b/B Browser is a useful optional extra for a desktop capturer, not a prerequisite for this web fix | recording | CATALOGUED — no extra required capture |

## Capture acceptance and coverage limits

- For each required row give recording URL, served source revision, viewport/theme, actual stop count and titles, real-app versus harness label, keys/actions, and observed composer/stop result. Keep auth cookies, tokens, startup pairing URLs and private data out of uploads.
- Check owner transitions from noninteractive prose/chrome; a focused button is excluded by type-to-focus regardless of the new claim and can hide a failure. After uppercase text focuses the composer, deliberately reclaim guide before the next guide-key assertion.
- For closing, distinguish release of the marker/listener from eventual unmount and from type-to-focus blocked by a still-closing modal. Record/log the immediate active state as well as the settled behavior; do not add arbitrary sleeps as proof.
- Existing command-palette, IME, already-prevented, Ctrl/Meta/Alt, terminal/model-picker, secret-input, and popup guards are unchanged; no need for a separate film per guard. Existing custom bare J/K binding precedence is intentional. R5's real editable control is the focused regression guard.
- No captures or test execution were audited in pass 1. No browser/computer use or server launch was attempted. Only this PR's source/metadata and supplied seed references were read. No repository files were modified.

FRICTION:
tool | web fetch tool could not open the two supplied ghdrop text URLs; direct read-only curl succeeded | allow text artifact retrieval in web fetch
brief | production RPC cannot accept an arbitrary prepared guide; exact-count/query-race fixtures require generation or labelled harness | provide a supported deterministic fixture provider or accept clearly labelled harness rows
forge | pushed PR metadata/checks refer to an older head than the supplied local candidate | record served local head in every evidence manifest

VERDICT: INSUFFICIENT R1, R2, R3, R4, R5, R6, R7, R8 recordings missing
