# PT2 Report Aftermath ROM Trace

This note tracks what the ROM does after the RCP emits an autonomous serial report from the `F870` report queue.

## Core Model

The RCP report path is:

```text
3E54 / 4046 enqueue selector into F870
3FD3 checks send gates
BAF2 dequeues/stages a report from F870 and E800
BA26 sends the six-byte SCI1 frame
BB46-BB51 arms the continuation/resend aftermath
```

The important consequence is that `BAF2` does not advance the report consumer cursor. The emitted report remains outstanding until the host sends a valid continuation command.

## Report Queue

| RAM | Role |
| --- | --- |
| `F870` | autonomous serial-report word ring |
| `F9B0` | producer cursor |
| `F9B5` | consumer/outstanding cursor |

Producer paths:

- `H'3E54`: when `R2.7` is set, deduplicates and appends `R3` to `F870`, then advances `F9B0`.
- `H'4046-H'4070`: when heartbeat/report cadence expires and the report queue is empty, appends selector `0x0000` to `F870`.

Consumer path:

- `H'BAF2` compares `F9B5` against `F9B0`.
- If equal, no report is pending.
- If different, it reads selector `F870[ F9B5 ]`, reads the report value from `E800[selector]`, stages the outgoing frame, and calls `BA26`.
- `BAF2` leaves `F9B5` unchanged.

Only continuation command `4`, `5`, or `6` advances `F9B5`, and only when `FAA2.3` is still set.

## Report Send Gates

`H'3FD3` allows `BAF2` only when:

- `FAA2 == 0`.
- `F9C0 == 0`.
- If `FAA5.7` is set, `F9C3 == 0`, meaning no partial RX frame is currently being assembled.

This means host RX traffic can block report sending while a session is active.

## Aftermath Window

After `BA26` sends the report frame, `H'BB46-H'BB51` arms the report aftermath:

| Address | Write | Meaning |
| --- | --- | --- |
| `H'BB00` | set `FAA2.3` | queued report needs continuation |
| `H'BB46` | `F9C6 = 0x01F4` | resend spacing countdown |
| `H'BB4C` | `F9C8 = 0x14` | resend/retry budget |
| `H'BB51` | `FAA3 = 0x80` | live resend/window marker |

While this is live, valid RX frames enter the continuation dispatcher because `FAA2 != 0`.

## Clean Continuation Consume

Commands `4`, `5`, and `6` all share the same report-consume pattern:

```text
if FAA2.3 set:
    F9B5 += 1
    clear F9B5.7
clear FAA3
clear FAA2
```

Handler addresses:

| Command | Handler | Consume block |
| --- | --- | --- |
| `4` | `H'BD0E` | `H'BD67-H'BD79` |
| `5` | `H'BD80` | `H'BDC2-H'BDD4` |
| `6` | `H'BDDB` | `H'BDED-H'BDFF` |

The ROM does not appear to require the continuation ACK selector to match the emitted report selector. The consume test is `FAA2.3`, not selector equality.

## Non-Clean Paths

Low commands `0/1/2/3` while `FAA2.3` is live:

- `H'BC5C` clears `FAA2.3`.
- If the bit was set, `H'BC63` clears `FAA3`.
- `H'BC67` re-enters initial dispatch.
- This does not advance `F9B5`.

Command `7`:

- Retransmits the previous finalized TX frame through `H'BE05-H'BE25`.
- Does not clear `FAA2/FAA3`.
- Does not advance `F9B5`.

TX/RX overlap interlock:

- At `H'BA84-H'BAA7`, TXI checks `FAA2.3 && FAA5.7 && F9C3 != 0`.
- If true, it clears `FAA2.3`, clears `FAA3`, disables TXI, and loads `F9C0=0x1F`.
- This collapses the report window without consuming `F9B5`.
- Bench implication: starting a host frame before the RCP has finished TX can destroy the very continuation window being targeted.

## Resend And Expiry

`H'BE9E-H'BEE8` manages the unconsumed report aftermath:

- Masks `FAA3` with `FAA5.7`.
- If the session gate is gone, `FAA3` becomes zero and `FAA2` is cleared.
- If `FAA3.7` is live and `F9C6 != 0`, it waits.
- If `F9C6 == 0` and `F9C8 != 0`, it decrements `F9C8`, reloads `F9C6=0x01F4`, clears `F9C3`, and calls `BA26` to resend the same finalized frame.
- If `F9C8 == 0`, it clears `F9C5`, forcing the broader session timeout path.

So an unconsumed report can be resent repeatedly, then eventually force the session watchdog to expire.

## Session Timeout

`F9C5` is the broad active-session watchdog:

- A complete six-byte RX frame reloads `F9C5=0x14` at `H'BB9E`.
- FRT2 decrements `F9C5` at `H'BF31-H'BF37`.
- `H'3FEF` observes expiry, clears `F9B5/F9B0`, clears `FAA5.7`, and if the gate was previously live calls `H'400C`.
- `H'400C -> H'4075 -> H'4217` clears broad session/display state and redraws `CONNECT:NOT ACT`.

Related timers:

| RAM | Role |
| --- | --- |
| `F9C0` | post-TX/report-send gate; decremented by FRT1 |
| `F9C1` | RX inter-byte timer; partial-frame timeout |
| `F9C4` | heartbeat/report enqueue cadence |
| `F9C5` | active serial-session watchdog |
| `F9C6/F9C8` | unconsumed report resend spacing/budget |

## Fake-CCU Implications

Best pure report ACK:

```text
05 00 40 00 00 1F
```

Rationale:

- Command `5` consumes the report cursor when `FAA2.3` is live.
- Selector `0x0040` is not one of the known command-5 special side-effect selectors.
- Value bytes are ignored by the generic command-5 consume path.

Same-selector command-5 ACKs are plausible for human readability, but not ROM-required:

```text
05 00 00 00 00 5F  ; ACK selector 0x0000
05 00 02 00 00 5D  ; ACK selector 0x0002
05 00 07 00 00 58  ; ACK selector 0x0007
05 00 15 00 00 4A  ; ACK selector 0x0015
05 01 0F 00 00 51  ; ACK selector 0x008F
```

Use command `4` only when the host intentionally wants to refresh primary/current state while consuming:

```text
04 00 00 80 00 DE  ; selector-zero active refresh
```

Use command `6` only when the host intentionally wants to refresh secondary feature gates while consuming:

```text
06 00 15 00 01 48  ; E400[0x0015] = 1
06 01 0F 18 00 4A  ; E400[0x008F] = 0x1800
```

Avoid command-5 special selectors as generic ACKs unless the side effect is desired:

```text
05 00 6C 00 00 33  ; COPY completion/exit sibling
05 00 6D 00 00 32  ; COPY IN PROGRESS/start
05 00 6E 00 00 31  ; special accepted, later handler is cleanup/no-op-like
```

## Proposed Normal Loop

A plausible fake-CCU report loop is:

1. Keep the serial format at `38400 8E1`.
2. Seed active state, especially selector zero.
3. Listen for a complete RCP TX frame.
4. Wait until the RCP frame is fully transmitted.
5. Quickly send a command-5 generic ACK before `F9C6/F9C8` resend handling starts.
6. Continue sending enough valid six-byte frames to reload `F9C5` before session expiry.
7. Add command-4/command-6 state refreshes only when we intentionally want to update lamps, displays, or menu gates.

This is the current best ROM-supported path for maintaining `CONNECT: OK` without accidentally consuming the report incorrectly or triggering COPY/menu side effects.

## Emulator Check

Reactive emulator testing supports this model:

- Seeded active state with command `0`, selector zero value `0x8080`.
- Waited for a report window where `FAA2.3` and `FAA3.7` were set and SCI1 TXI was idle.
- Sent `05 00 40 00 00 1F`.
- The ACK path reached the command-5 consume block and advanced `F9B5`, then cleared `FAA3` and `FAA2`.
- Repeating that reactive loop 12 times kept the emulated LCD at `CONNECT:  OK`.

Observed clean consume shape after each ACK:

```text
before: FAA2=08 FAA3=80 F9B5=N
after:  FAA2=00 FAA3=00 F9B5=N+1
```

A fixed-delay or extra-guard strategy was less reliable. In one run, waiting an additional 1 ms after TX idle before sending the ACK only consumed two reports before falling back to `CONNECT:NOT ACT`. That result should not be overfit as an exact real-device limit, but it reinforces the ROM timing lesson: ACK as a reaction to a finished frame, not as a loose periodic delay.
