 
 (s/def ::block (s/keys :req [::length
                              ::start-pos
-                             ::time]))
+                             ::time
+                             ::transmissions]))
 (s/def ::blocks (s/and (s/coll-of ::block)
                        ;; Actually, the length must be a power of 2
                        ;; TODO: Improve this spec!
                        ;; (Reference implementation uses 128)
                        #(= (rem (count %) 2) 0)))
 
-;;; Index into the start of a circular queue
-;;; Q: Is this a good idea?
-(s/def ::block-first int?)
-
-;; Number of outgoing blocks being tracked
-(s/def ::block-num integer?)
-
 ;; If nonzero: minimum of active ::time values
-(s/def ::earliest-time integer?)
-
-(s/def ::state (s/keys ::req [::block-first
-                              ::block-num
-                              ::blocks
-                              ::earliest-time]))
+(s/def ::earliest-time int?)
+
+;; Number of initial bytes sent and fully acknowledged
+(s/def ::send-acked int?)
+;; Number of additional bytes to send (i.e. haven't been sent yet)
+(s/def ::send-bytes int?)
+;; within sendbytes, number of bytes absorbed into blocks
+(s/def ::send-processed int?)
+;; Those 3 really swirld around the sendbuf array/circular queue
+;; For this pass, at least, I'm trying to avoid anything along those lines
+
+;; 2048 for normal EOF after sendbytes
+;; 4096 for error after sendbytes
+;; Dual-purposing a magic constant bit for both the
+;; over-wire communications flag and the
+;; internal behavioral flow-controller
+;; chafes.
+;; TODO: Don't.
+(s/def ::send-eof #{false ::normal ::error})
+(s/def ::send-eof-processed boolean?)
+(s/def ::send-eof-acked boolean?)
+
+;; Totally undocumented (so far)
+(s/def ::total-blocks int?)
+(s/def ::total-block-transmissions int?)
+
+(s/def ::state (s/keys ::req [::blocks
+                              ::earliest-time
+                              ::send-eof
+                              ::send-eof-processed
+                              ::send-eof-acked
+                              ::total-blocks
+                              ::total-block-transmissions]))
+
+(defn initial-state
+  ;; TODO: This should probably just be public
+  []
+  {::blocks []
+   ::earliest-time 0
+   ::send-eof false
+   ::send-eof-processed false
+   ::send-eof-acked false
+   ::total-blocks 0
+   ::total-block-transmissions 0})
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Internal


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Magic constants

(def incoming
  "Number of blocks in inbound queue

  Must be a power of 2"
  64)

(def outgoing
  "Number of blocks in outbound queue

Must be a power of 2"
  128)

(def outgoing-1
  "Decremented size of outbound queue

Used w/ bitwise-and to calculate modulo and wrap circular index

Because this is used more often than outgoing"
  (dec outgoing))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Specs

;;;                        sendbytes
;;;                        sendprocessed
;;;                        blockfirst
      (let [[to-drop to-keep] (split-with #(= 0 (::time %)) acked)
            dropped-block-lengths (apply + (map ::length to-drop))
            state (update state ::send-acked + dropped-block-lengths)
            state (update state ::send-bytes - dropped-block-lengths)
            state (update state ::send-processed - dropped-block-lengths)
;;;           177-182: Possibly set sendeofacked flag
            state (or (when (and send-eof
                                 (= start 0)
                                 (> stop (+ (::send-acked state)
                                            (::send-bytes state)))
                                 (not send-eof-acked))
                        (update state ::send-eof-acked true))
                      state)]
;;;           183: earliestblocktime_compute()
        (assoc state ::earliest-time (earliest-block-time blocks))))
    ;;; No change
    state))

