Hmmmm. It all looks very reasonable,

Code
./unidasm -arch m6502  -basepc 0xc800 grappler_2716_U6_eps_1c1982.bin | grep c08 -A 6 -B 5
cbcb: b9 81 c0  lda $c081, y
cbce: 29 04     and #$04
cbd0: ea        nop                       // guess they don't care about paper out
cbd1: ea        nop
cbd2: b9 81 c0  lda $c081, y
cbd5: 29 02     and #$02           //  printer not selected
cbd7: f0 46     beq $cc1f
cbd9: b9 81 c0  lda $c081, y
cbdc: 29 08     and #$08         //  loop here if busy
cbde: d0 f9     bne $cbd9
cbe0: bd 38 07  lda $0738, x
cbe3: 29 08     and #$08
cbe5: f0 04     beq $cbeb

Just running one CTRL+I G will start printing garbage.

Does the ap2000 have to synchronize itself just as the grappler is synchronizing?

It seems that the grappler is doing all the synchronizing, and the ap2000 and its e05a30 device doesn't have to synchronize.
Code
machine().scheduler().synchronize(timer_expired_delegate(FUNC(a2bus_grappler_device::set_strobe), this), 0);