Serial Test Logs from the Wrong Boot: Mark Each Session Before Matching a PASS String
Accept a serial PASS only when a complete result record belongs to the expected unit, qualified boot instance, current test request and test identity. Clearing a buffer or reopening a port does not create that relationship. Stale output can arrive after either action, and a plain success string carries no evidence about which run produced it.
The serial-library reference is pySerial 3.5. Nine synthetic framed-record checks were executed with Python 3.12.14; no serial port was opened and pySerial itself was not executed. The proposed firmware handshake and reset qualification require implementation and tests on the actual device.
Identify the different generations
Keep port connection, device boot and test request identities separate. A USB serial connection can be replaced while the device keeps running. A device can reboot while the host port stays open. Multiple tests can run during one boot.
Assign a fresh host request identifier that is not reused within the retained evidence scope. Require the firmware to return it as part of a structured test-result record, alongside its unit identity and boot identity. The identifier must travel through the actual test operation, not merely appear in an echoed command.
Define how boot identity is created and when it changes. A counter that resets to zero every boot is not globally unique. A host challenge proves a response is associated with that challenge only under the protocol’s rules; it does not alone prove that a requested hardware reset actually occurred.

Qualify the reset and handshake independently
Observe the product’s approved reset or power-cycle condition, then establish the expected boot identity through the defined handshake. If a unique boot marker is unavailable, use a qualified alternative and state its limitations. Do not infer a new boot solely from reopening a console.
The pySerial 3.5 API documentation warns that some operating systems or drivers activate RTS/DTR when opening a port, and line-state glitches can occur. Where those signals influence reset or boot mode, port opening is part of the hardware sequence rather than a harmless logging action.
Record the port configuration and line-control policy. Do not toggle control signals experimentally on production equipment. A test that unintentionally resets the board when connecting can produce a convincing boot log while exercising a different sequence from the one intended.
Treat buffer clearing as housekeeping
pySerial documents reset_input_buffer as discarding the input buffer’s contents. That does not prevent the device from transmitting old queued output afterward, nor does it erase data already retained by the test application’s parser.
The same version’s RFC 2217 notes explicitly describe additional network/server buffering and delayed buffer operations. If the fixture uses a remote console, include those layers in the evidence model. A local in_waiting value is not an end-to-end statement that no older bytes exist.
Reset the application’s partial-frame state when its connection generation becomes invalid. Preserve discarded diagnostic bytes separately when useful, but do not carry an unterminated fragment into a new session and accidentally construct a valid result from two different generations.
Define one complete terminal record
An illustrative record contains unit, boot, run, test and result fields, terminated by a newline. The production protocol needs explicit encoding, maximum record size, allowed fields, escaping and duplicate handling. Arbitrary console diagnostics should not share the acceptance grammar merely because they contain the word PASS.
Read until a complete frame or an explicit bounded failure. In pySerial 3.5’s read_until implementation, the method can stop at the delimiter, size bound or timeout. A returned nonempty byte string is therefore not proof that the delimiter arrived.
Only evaluate a terminal record after framing and field validation succeed. Treat malformed, truncated, unexpected or out-of-session output as diagnostic evidence, not as an implicit fail or pass. Missing required results should become a distinct incomplete-test outcome.
Read the executed stale-result controls
The model expected synthetic unit U1, boot B2, run N2 and test T1. It accepted one complete JSON-line record with those fields and a PASS result. The expected tuple was supplied by the model; no real identity or boot observation established it.
| Synthetic input | Outcome | Reason |
|---|---|---|
| Current complete record. | Accepted by the predicate. | All expected fields and terminator match. |
| Older run or older boot. | Rejected. | Successful text belongs to another generation. |
| Wrong unit or wrong test. | Rejected. | Result is outside the current binding. |
| Plain PASS text or unterminated record. | Rejected. | Required structure or complete framing is absent. |
| Explicit FAIL. | Not accepted as a pass. | Terminal result is unsuccessful. |
| Matching record after reconnect disarms acceptance. | Rejected. | A fresh handshake is required. |
All nine checks passed. This is a narrow complete-record predicate, not a full streaming parser. It does not test byte-by-byte buffering, duplicate terminal records, maximum-size enforcement or malicious forgery; those belong in the implementation’s wider test suite.
Invalidate the session on meaningful changes
Disarm result acceptance on disconnect, unexpected boot marker, unit replacement or cancellation. Start a new request generation only after the binding is re-established. A late response to the previous request must remain associated with that previous attempt.
Prevent another reader or writer from competing for the same console. A second process can consume the expected marker or inject a command that changes state. Exclusive ownership must cover the actual fixture access path, not only a lock inside one test function.
For a request timeout, preserve the uncertain result rather than automatically issuing the same consequential test again. Some tests alter calibration, nonvolatile state or attached equipment. Their retry policy must be qualified separately from serial parsing.
Qualify the complete evidence path
Use fake streams to split records at every relevant boundary, delay old records, concatenate messages and inject reconnects. Then test the real console with controlled reset and buffering conditions on recoverable hardware. Confirm that a stale success never satisfies a new request and that a valid current result remains usable despite ordinary diagnostic output.
The resulting contract should state exactly what establishes the boot, which request the result answers and why the frame is complete. This makes the PASS meaningful without claiming that a buffer flush, timestamp or success substring proves a fresh test occurred.