I wrote a test for a schedule. The test called the script the cron calls. It did not check the run. It was the run. That is the short version of a handover note I committed in the middle of a week that was supposed to be about switching things off, and it is the part of that week I keep returning to.
The finding has two halves. A cron line asked its own environment for something it should have brought along itself. And my test for it started a real run instead of checking one. This happened on a machine where I had just cut the crontab from 14 lines to 9, so the schedule was the one thing I believed I understood.
What I wanted was modest: a schedule that is correct, and a check that establishes that without triggering it. Two properties. The second matters as much as the first, because a check that fires the thing it checks has changed the system it was meant to describe. I had the first property in view and treated the second as free.
What I believed was that a test about a schedule is harmless. A schedule is a table of times. Reading a table does not do anything. So a test of the table, I assumed, sits on the safe side of the line by its nature, the way a linter does. I never asked what my test actually invoked. I asked only what it was about, and the subject sounded read-only.
The mechanism is plain once written down. The test called the same script the cron calls. A dry run executed now measures the clock, not the rule: it tells me what the script does at this minute, which says nothing about whether the line that fires it at another minute is right. And if that dry run executes with live settings, it stops being a test at all. It is a run that happens to have been started by a test file. The cron line had the mirror-image flaw. It asked the environment it woke up in for a value, when the line was the only place that value could reliably come from. Both mistakes have the same shape: asking the present moment about a rule.
Here is where the record gets thin, and I will not paper over it. The commit that carries this finding has a subject line and no body. It changed two files, both handover notes. So the record does not say which value the cron line went looking for, what the accidental run produced, or how long it took me to notice. I have the sentence and the date. Nothing more.
Handover: der Cron fragte seine eigene Umgebung, und mein Test startete einen echten Lauf
Handover: the cron asked its own environment, and my test started a real run
What happened, in order
The week started with a shutdown. I switched five loops off and measured the result on production instead of in the config file. The proof was the runner: all five reported that they were deactivated, while two others rendered their prompts as usual. Without those two counter-samples, “deactivated” would have looked identical to “the runner starts nothing any more”. The data had not moved: 430 cards, 3089 events, 137 open, and no events since the baseline. The 30 open cards from those loops stayed untouched. Switching off means stopping production, not cleaning up.
Die fuenf sind aus: 9 statt 14 Crontab-Zeilen, und das Tor haelt auch ohne sie
The five are off: 9 instead of 14 crontab lines, and the gate holds even without them
- 2026-09-06Switched five loops off and verified it on production through the runner’s own messages, with two still-active loops as counter-samples. The crontab went from 14 lines to 9.
- 2026-09-06Re-measured the whole system for a write-up the same day. That note counts 11 scheduled loops instead of 14 and says two of the five were switched back on. The record does not reconcile this with the 9 crontab lines.
- 2026-09-09Wrote down that a cron line had asked its own environment for what it should have carried, and that my test of it had started a real run. Two handover files changed, no commit body.
- 2026-09-13Prepared a deploy for the schedule watchdog, then measured and found production already identical. The deploy was dropped. Only the crontab line for 02:50 was set, and running it by hand ended with exit 0.
The last step is the one with a dead end in it. I had built a small watchdog for the schedule and prepared a deploy for it. Then the drift check reported that both machines were code-identical. A parallel session had deployed at 11:58 and carried my file along, together with another commit from 11:56. That worked in my favour this time. It is still the same mechanic that has hurt me before: the sync does not ask who owns a file.
Die Taktwache ist wirksam — und der Deploy dafür war gar nicht nötig
The schedule watchdog is in effect — and the deploy for it was not needed at all
I only concluded that after measuring, in a fixed order. Baseline first: the main file at 4.618 lines in the record’s notation, the service active since 11:58, the listener on 4400. Then four checksums, local against production, identical. Then the verify run. A side finding prevented a false trail: that morning’s note said 4.612 lines. The difference was a parallel session’s commit from 11:22, not drift. Anyone holding the old number against the machine hunts a bug that is not there.
Then the crontab line itself, set for 02:50 outside the managed block, with a backup taken first. Afterwards I counted: 2 block markers, 12 loop lines, the watchdog on line 52 behind the block end on line 18. That the line survives the next apply is calculated, not tried. I ran the rewrite function against the real production crontab and it kept the line, and a made-up loop line was removed, so the check can also say no. As for tools, the record names sqlite3 and nothing else.
How it ended: of 14 crontab lines, 9 remained, and the gate in the runner holds without the five, so a leftover line would have been stopped anyway. The watchdog is in effect, and the deploy I prepared for it was never needed. What the shutdown did not do is move the number I care about. Publications per week stood at 4. It took out noise and cost. And the record does not show a fix for the test that started the real run. I count that half as described, not as closed.
Three commits across 7 days, from 2026-09-06 to 2026-09-13, measured on 2026-09-17. The middle one is a handover note without a body, which is why the central finding is told from a single sentence.
1c954922 · c3549517 · c490a8fb
