The experiment that worked and cannot be repeated

By Lior Rabanian · · 8 min read
  • Method
  • Notes
  • Learning

It worked on Tuesday.

You have the number, and it is a good number, and you were pleased with it. Today the same script on the same machine produces something else, and the gap between the two is larger than anything you can explain. Nothing in the repository changed. You are now going to spend two days finding out what did.

The answer, almost always, is something that was never in the code: a parameter you edited by hand and put back, a file you regenerated, a threshold you nudged at eleven at night, a library that updated underneath you, the one run where you used the cleaned data rather than the raw.

None of those are in version control. All of them were known to you, briefly, on Tuesday.

What a log is actually for

The laboratory notebook is one of the oldest pieces of research infrastructure there is, and the convention around it is unusually strict: dated entries, written at the time, in ink, never erased, in enough detail that somebody else could repeat the work.

Every one of those rules exists because of a specific way research goes wrong, and none of them stop applying because the experiment is now a script rather than a bench. If anything the computational version is more exposed, because the number of silent moving parts is larger and none of them leave a smell or a stain to remind you they were there.

The purpose is not tidiness. It is that a result which cannot be repeated is not yet a result, and the thing standing between you and repeatability is usually one unrecorded decision.

The same code and the same data producing two different numbers, because of one change that was never written down
Everything that was tracked is identical. The difference is in the row nobody thought to record.

What one entry needs

Per run, or per experiment, or per session at the bench — whatever your unit of work is. The test is simple: could a competent stranger, or you in eight months, do this again and get the same answer?

The date and the question. What you were trying to find out. One sentence, and it is worth more than it looks, because in three months the runs blur into each other and the question is what tells them apart.

What version of everything. The commit hash, the data file and its version or checksum, the environment or container, the versions of anything that matters. If you edited something by hand, that is the most important line in the entry, precisely because nothing else will ever record it.

The parameters. All of them, including the ones you did not change. "Defaults" is not a record, because defaults change.

What you actually did, including the parts that were not the plan. The rerun after the crash. The two rows dropped because they were obviously wrong. The manual fix at the end. These are the steps that get silently omitted, and they are the steps that most often explain the discrepancy.

What came out. The number, the figure, where the output was written.

What you think it means — marked clearly as interpretation, and separable from everything above it.

That last separation matters more than it sounds. Observation and inference decay at different rates: what you did stays true forever, and what you concluded on the day is frequently wrong. A log that blends them gives you no way, later, to keep the one and discard the other.

Write it before you know whether it worked

This is the rule that improves the record most and the one nobody follows.

Once you know the outcome, you write a different entry. Not dishonestly — the process is invisible from the inside. A run that succeeded gets written up as though the path to it were direct. A run that failed gets a shorter entry, because it feels like nothing happened. The awkward steps, the reruns, the thing you tried first, quietly vanish from the record in proportion to how well the result turned out.

So write the setup before you press go: the question, the versions, the parameters, what you expect. Then add the outcome underneath. It takes two minutes and it is the only reliable defence against hindsight editing your own notes.

It is the same habit as writing something down the first time you work it out, moved thirty seconds earlier, to the moment before you have an opinion about it.

Negative results are the ones worth keeping

The most valuable entries in a research log are the things that did not work, and they are the least likely to be written, because a failed run feels like a day with nothing to show for it.

Five months later you will have the idea again. It is a good idea — that is why you had it twice — and without a record you will spend another three days rediscovering why it does not work. Multiply by a research group, where the person who tried it has since graduated, and this is a substantial fraction of all wasted effort in science.

The entry is one line. "Tried the weighted version; it makes no difference, because the weights are almost uniform in this sample." That sentence is worth days, and it is worth more to the next person than to you.

Version control does half of this

Be fair to git: it records the code exactly, it records when it changed, and it lets you go back. That is a large part of the problem solved, and if you are not using it for research code, start there before reading anything else in this article.

What it does not record is the rest of the entry. It does not know why you made the change, which run produced figure 3, what data file was mounted, what you typed at the prompt, what the environment looked like, or which of eleven branches was the one that produced the number in the draft. A commit message is a note about a change to the code; a log entry is a note about a piece of work. They are different objects and one does not substitute for the other.

The join between them is the commit hash, written into the log entry. One line, and it makes both records navigable from either end.

Every figure should name its run

This is the specific failure that hurts most, and it happens late.

You are assembling a paper. There are eleven figures. Someone asks what the sample size was for figure 4, or a reviewer asks you to regenerate it with one change, and it turns out nobody can say with certainty which run produced it. The figure is nine months old, the script has moved on four times, and the number in the caption cannot be re-derived.

The fix is one line per figure, kept with the figure: which run, which commit, which data, which script. If you do only one thing from this article after the negative-results line, do this one, because it is the one that turns into a genuine crisis rather than an inconvenience.

A dated log with entries appended underneath the facts that do not change
Appended as you go, never rewritten. A log you tidy is a summary, and a summary is what you already had.

Append, never rewrite

The entries are added and not edited. If March was wrong, September says so; March stays as it was.

The reason is not ceremony. A log that is revised in the light of what you later learned is no longer evidence of anything — it is a summary, and you already had one of those in your head, which is what made it unreliable. The value of the record is precisely that it was written before you knew how the story ended.

This is the same discipline that makes a decision journal worth keeping, for the same reason: the entry is useful because it cannot flatter you afterwards.

Where it should live

Unpublished results, in a searchable pile, for the duration of a project that may run for years.

The requirements are unglamorous. It must open fast enough that you use it mid-task, because a log you open only at the end of the day is a log written from memory. It must still work when the network does not, on a bench, in a field site, on a train. It must be searchable across years, because the query is always "when did I last see this error" and never "which folder is it in". And it must be exportable, because the project will outlive whatever you are using and possibly your access to the institution's systems.

Local, plain, no account, one file you can copy. That is the ordinary local-first case, and research is where it happens to bite hardest, because the time horizons are long and the data is often governed by rules about where it may be stored. Whatever you choose, back it up somewhere that is not the laptop — a lost research log is not recoverable by any means at all.

The honest version

Nobody does all of this. The people with the best records in any research group keep maybe two-thirds of it, and they keep it because they were burned once, badly, and the memory is still fresh.

The realistic version is three lines before each run — the question, the versions, the parameters — and one line after, including the failures. That is under two minutes per run and it catches most of what goes wrong.

The rest of it, you will add gradually, each item after the specific week it would have saved you. That is how everybody actually learns this, and there is no shortcut, except possibly reading the list above and deciding to believe it early.

If you want one place for it that opens instantly, appends without ceremony and searches across four years of it, Cyanote is $7.99, once. The literature notes are a separate pile with a separate job, and what happens to both of them after three or four years is its own problem.

Try it