Unit 10 · lesson
Build the Timeline Before You Write the Diagnosis
When several logs, exceptions, test results, and runtime observations exist, the hardest part is often not collecting more data. It is keeping the records in the right order and refusing to invent connections that the evidence does not show.
A diagnostic timeline organizes observations by source and time so you can see what happened before, during, and after a failure.
The timeline is not the diagnosis. It is the evidence surface from which a diagnosis can be argued.
Start with separate records
Imagine you have four pieces of evidence.
JUnit regression result
continuesExactlyAtBoundary PASSED
This confirms the tested strict-boundary rule for the JUnit case.
WPILib data log
42.120 rawRangeMeters=3.70
42.121 range update rejected id=range-front
42.121 sourceHealthy=false
42.160 rawRangeMeters=0.41
42.161 acceptedRangeMeters=0.41
42.161 sourceHealthy=true
This records application telemetry and modeled health-state changes.
ROS 2 graph inspection
/sensor_bridge
/motor_guard
This records node names visible in one controlled graph snapshot.
ROS 2 supplied log record
42.100 WARN sensor_bridge "range source timeout count=1"
This records a warning from a ROS logger in the supplied case.
Each record is useful. None should be silently promoted into another record's evidence layer.
Normalize the timeline
Put the observations into one table while preserving the source:
| Time | Source | Observation |
|---|---|---|
| test run | JUnit | strict boundary regression test passed |
| 42.100 | ROS logger | sensor_bridge warning about one timeout |
| 42.120 | WPILib data log | raw range 3.70 m recorded |
| 42.121 | WPILib data log | update rejected for range-front |
| 42.121 | WPILib data log | modeled source health became false |
| 42.160 | WPILib data log | raw range 0.41 m recorded |
| 42.161 | WPILib data log | 0.41 m accepted |
| 42.161 | WPILib data log | modeled source health became true |
| snapshot | ROS graph | /sensor_bridge and /motor_guard visible |
The table makes order visible without changing the meaning of any record.
Do not force incomparable clocks into fake precision
Not every source uses the same clock.
A JUnit test report may not share timestamps with a robot runtime log. A supplied graph snapshot may have no useful timestamp at all. Different machines can also have clocks that are not synchronized.
If two records cannot be aligned precisely, say so.
Do not invent timestamps just to make the table look complete.
Use labels such as:
before runtime case
runtime timestamp
snapshot after case
clock not synchronized
when that is what the evidence supports.
Separate observation from interpretation
Observation:
42.100 ROS logger warned about one timeout.
Interpretation:
The timeout caused the later Java range rejection.
The second statement is a causal hypothesis, not a direct observation.
To support it, you would need evidence that the ROS data path feeds the Java component and that the timeout could produce the specific 3.70 m input.
Until then, write:
The ROS warning occurred before the WPILib rejection in the supplied timeline. A causal relationship has not been established.
That sentence is technically stronger because it preserves what is known and what is not.
Use the timeline to generate the next test
A good diagnostic record should reduce the search space.
From the example, possible next actions include:
- inspect the raw data source before the Java validation layer;
- verify the Java-to-ROS integration path, if one is supposed to exist;
- inspect unit conversion;
- reproduce the timeout and see whether the invalid value appears again;
- compare with additional sensor samples;
- inspect the configuration that defines
2.00 mas the maximum.
The next action should answer a specific uncertainty.
"Look at more logs" is not a plan.
Evidence can contradict your first theory
Suppose your first theory is:
Every ROS timeout produces an invalid
3.70 mreading.
Then a later record shows:
44.200 WARN sensor_bridge "range source timeout count=1"
44.220 WPILib rawRangeMeters=0.40
44.221 acceptedRangeMeters=0.40
That evidence weakens the original theory.
Do not discard it because it complicates the story.
A diagnosis should survive contradictory cases or be revised.
Build competing hypotheses
For the 3.70 m incident, you might consider:
Hypothesis A: unit conversion error
Prediction:
similar values should appear when a specific conversion path runs
Evidence to seek:
raw source before conversion and converted value after conversion
Hypothesis B: transient source anomaly
Prediction:
one or a few isolated invalid samples among otherwise valid readings
Evidence to seek:
longer raw-value history and source diagnostics
Hypothesis C: configuration mismatch
Prediction:
values are legitimate for the source but exceed the software's configured limit
Evidence to seek:
sensor specification/configuration and configured min/max values
A useful diagnosis attempts to distinguish among hypotheses rather than selecting the first plausible one.
A recovery result needs its own evidence
Suppose the software marks the source healthy again at 42.161.
That supports:
The application's modeled health state returned to healthy after accepting
0.41 m.
It does not prove:
The physical sensor recovered.
To claim physical recovery, you would want evidence tied to the physical mechanism or device behavior.
The same discipline applies to motor commands, network recovery, and ROS processes.
Tests and logs answer different time questions
JUnit asks:
Does this controlled case produce the expected behavior when I run it now?
A runtime log asks:
What did the instrumented system record during this particular run?
Both are important.
A failing runtime incident may inspire a new regression test. The new test then protects the software rule against the same class of defect in future edits.
That is a productive loop between testing and diagnosis without confusing the two evidence types.
Worked incident summary
Using the example timeline, a defensible summary could be:
The strict caution-boundary JUnit regression test passed before the runtime case. During the supplied runtime timeline, a ROS logger named
sensor_bridgerecorded one timeout warning. Twenty milliseconds later, the WPILib application recorded a raw3.70 mvalue, rejected it, and marked its modeled range source unhealthy. A later0.41 minput was accepted and the modeled health state returned to healthy. The records do not establish that the ROS timeout caused the invalid Java-side value or that physical hardware failed and recovered.
Notice what the summary does not do.
It does not use the word "because" where causation has not been demonstrated.
Your pre-lab challenge
You receive:
08.100 WPILib batteryRawPercent=140.0
08.101 WPILib message="battery update rejected"
08.101 WPILib batteryStatePercent=76.0
08.105 ROS INFO power_monitor "voltage telemetry available"
Create a four-row timeline with explicit sources.
Then write:
- one observation that is definitely supported;
- one plausible hypothesis;
- one causal claim that is not supported;
- one next observation that would help distinguish the hypothesis.
In the lab, you will build this kind of record from an injected Java failure, WPILib-style log evidence, test evidence, and a controlled ROS runtime observation.