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:

TimeSourceObservation
test runJUnitstrict boundary regression test passed
42.100ROS loggersensor_bridge warning about one timeout
42.120WPILib data lograw range 3.70 m recorded
42.121WPILib data logupdate rejected for range-front
42.121WPILib data logmodeled source health became false
42.160WPILib data lograw range 0.41 m recorded
42.161WPILib data log0.41 m accepted
42.161WPILib data logmodeled source health became true
snapshotROS 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 m as 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 m reading.

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_bridge recorded one timeout warning. Twenty milliseconds later, the WPILib application recorded a raw 3.70 m value, rejected it, and marked its modeled range source unhealthy. A later 0.41 m input 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:

  1. one observation that is definitely supported;
  2. one plausible hypothesis;
  3. one causal claim that is not supported;
  4. 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.