Skip to content

nap.dart: leading edge of the record is unguarded, unlike the trailing edge #40

Description

@abdulsaheel

Summary

immobilityMask / detectNaps guard the trailing edge of the record but not the leading edge, so edge has to guess at the boundary with a wall-clock heuristic instead of being told.

The asymmetry

nap.dart handles a bout running past the end of the record properly — it marks it unfinished and defers it, and propagates that backward through napChainGapSec so a chained fragment is deferred too. That is exactly right.

At the other end there is no equivalent, because stillAt short-circuits its own discontinuity check at k == 0:

bool stillAt(int k) =>
    mask.deltaDeg[k] < thr && (k == 0 || absAt(k) - absAt(k - 1) == 1);

So a bout that was already in progress when the record opened is emitted as if it started there, with no way for the caller to tell the difference.

Why it matters downstream

edge slices a day's nap window at local midnight, so index 0 is the day boundary. A nap straddling midnight is emitted whole by the day that owns it and then re-detected as a fresh bout at index 0 by the next day — double-counted, with its minutes subtracted from both days' sleep need.

edge currently works around this (OpenStrap/edge#204) by dropping an index-0 bout when the record is contiguous into midnight, judged by a 60-second timestamp tolerance. That is a guess, and it has a known residual: if the band only starts recording at midnight, the previous day never saw the bout either, so both days drop it and a real nap is lost.

What would fix it properly

Expose leading-edge-unfinished the same way the trailing edge already is — e.g. a startsAtRecordEdge flag on NapWindow, or extend the existing unfinished concept to both ends. The caller can then defer on evidence rather than infer from a timestamp tolerance, and the residual disappears.

ImmobilityMask already carries immobileUnknown for undecidable seconds, which is the same idea — index 0 is undecidable in exactly that sense.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions