vibeapp.win

What brokeUpdated 3 October 2026

The camera aimed twice at a stale box and zoomed blind

In one morning the monitoring app's close-up job showed three faults: it zoomed in even when it had no target box, it read focus after a fixed 500 ms pause, and it corrected twice for a box the detector had not yet refreshed. Once the aiming decision was logged at info level, the log showed why the camera overshot.

The short version

What went wrongThe close-up job zoomed with no target box, read focus after a fixed 500 ms pause, and corrected twice for a stale box. The aiming decision was logged at debug, so none of this showed.

How we found itThe first real close-up missed. Logging each pulse at info showed the zoom with no box, identical boxes in two pulses one second apart, and a soft frame taken during autofocus.

The rule nowLog the aiming decision at info, zoom only after a box was seen, stop when the box matches the last round, and wait for focus to settle with a ceiling instead of a fixed pause.

This post documents something Claude got wrong. The claim rests on a commit or a file, not on memory. All of Claude's mistakes

The monitoring app has a job that tries to take a close-up. When the detector reports a target, the job reads its bounding box and nudges the camera toward it in short pulses. Once the target is centred it zooms in and grabs a frame. On 23 August 2026 the first real close-ups came back wrong. Two commits that morning, about 47 minutes apart, show how we found out why and what we changed.

Step one: the log could not answer the question

The first real close-up missed its target. The commit from 09:41 puts the problem plainly: the log “could not say whether the camera swung the wrong way or simply too far”. Every line in the centring loop was logged at debug level, and the app runs at info. In the commit’s words: “The one decision the whole job exists for was unobservable.”

So the first fix changed no behaviour. It made the job visible. Each centring pulse now logs at info: the box it read, the computed error on both axes, the pan and tilt values it sent, and how long the pulse lasted. The commit gives the reason in one line: “A pulse that does not record what it aimed at cannot be debugged.”

Step two: it zoomed even when it had no target

While making the loop visible, we found a second fault in the same function. If the detector had no box for the object, the centring step returned early, and then the zoom ran anyway. The commit says the camera zoomed in blind.

That is worse than doing nothing. The wide frame the app already had is more useful than a blind close-up. A blind zoom also moves the camera away from its normal view for no gain. After the fix, the centring step reports whether it ever saw a box. The zoom runs only if it did. Otherwise the job logs a warning and takes a wide frame.

Step three: the new log showed the same box twice

With aiming logged at info, the next miss could be read straight from the log. The commit from 10:28 describes it: the target ended up at the far edge of the frame. Two pulses one second apart had both read the same box, and both had sent the same pan value.

The detector had not refreshed the box between the two pulses. The job took the stale box to mean the target was still off-centre and corrected for the same error a second time. The commit says it “moved the camera twice as far as the error called for.”

The fix is a simple comparison. If the box is identical to the one from the previous round, the job reads that as “no new information”, not as “the target has not moved”. It stops the loop and logs that it is holding still rather than doubling the pulse.

Step four: focus was read on a timer

The same commit fixes a separate fault. The close-up was soft across the whole frame. It had been taken 500 ms after the zoom, while autofocus was still hunting.

A fixed pause has a built-in tradeoff. To be safe it has to be set to the worst case, and then you pay for the worst case on every frame. The earlier commit had found that the camera exposes no focus control over the standard interface the app uses. But the camera’s own interface does report a focus position. The job now polls that value every 200 ms and treats focus as settled after two identical readings in a row. One reading is not enough, because focus can pause briefly in the middle of a hunt. After 4 seconds the job takes the frame anyway. It also logs the elapsed time and whether focus actually settled, “so it can be measured instead of assumed.”

Who got it wrong

The 10:28 commit calls its two fixes “two real faults”; the missing guard came from the earlier commit. They describe what the code did and why that was wrong. Henning writes no code himself, so the faults were in Claude’s code. The record also shows how the faults were found: by running the job against reality, and, for the stale box, through the aiming decision logged at info level.

This post covers what those two commits found and fixed.

The rule that came out of it

  • Log the aiming decision at info. If a job exists to make one decision, that decision has to be visible at the log level you actually run. Record what the job read, what it calculated and what it sent.
  • Stop the loop when the box is identical to the previous round. A box that has not changed most likely means the input has not been refreshed. It is not new evidence, and correcting for it again doubles the move.
  • Zoom only when a box has been seen. With no target, the wide frame is the better result.
  • Wait for the focus position to stop changing instead of a fixed pause. Use the signal the hardware gives you, set a ceiling, and log how long it took.

Corrections

  1. Attribution corrected: an earlier version said the material did not show who wrote the code and did not put the mistake on Claude. Henning writes no code himself; the code was written by Claude.