Skip to content

feat(forecast): the night is not runway — an hour shape for the walk - #33

Merged
lroolle merged 1 commit into
mainfrom
feat/hour-profile
Sep 1, 2026
Merged

feat(forecast): the night is not runway — an hour shape for the walk#33
lroolle merged 1 commit into
mainfrom
feat/hour-profile

Conversation

@lroolle

@lroolle lroolle commented Sep 1, 2026

Copy link
Copy Markdown
Member

forecast.cache gains hour_profile: 24 local-hour burn multipliers (mean 1, floor 0.1, same envelope pass + 14d EWMA, today excluded). The learned walk steps hour-by-hour, so dry-outs land where the reader can act on them instead of mid-sleep; the surplus feasibility check counts awake seconds only; the budget line gains ~N awake and rations by it; report states the learned rhythm.

  • Schema stays 2 (additive field; absent/invalid reads as flat — bit-identical to v0.35.0, regression-pinned).
  • REST_MULT_MAX=0.25 is part of the cache contract (docs/api/state-dir.md); ccpace v0.4.0 implements the same build/read rules — cross-writer parity verified exact on a shared fixture.
  • L1 blend now ends at exactly 24h (day-stepping let it run to 47h); called out in the CHANGELOG.
  • 458 bats passing (11 new), shellcheck clean.

Smoked on a 259-day real corpus (26,770 samples, 1.1s build): learned rhythm: rest ~12:00-19:00 · 17h awake/day; at 85% with 25h left the dry-out moves Tue 16:40 (mid-rest) → Tue 12:40 (end of active morning).

🤖 Generated with Claude Code

Claude Code can work around the clock; the human cannot, and every
projection this script made burned flat through the night. Four
measured consequences: `7d dry ~Thu 03:00`, which is a false alarm at
23:00 and a missed warning at 09:00; an L1 blend projecting a hot day's
rate through eight idle hours; "spend it" at 23:00 for a surplus no
waking hour can reach; and a ration dividing the week by windows you
sleep through. The corpus already held the answer — burn credited by the
envelope pass carries a timestamp, and hours that never burn across
weeks are rest.

`forecast.cache` gains `hour_profile`: 24 burn multipliers, local hour
"0".."23", mean 1, so the rate at hour h is `weekday_rate x mult[h]` and
integrating any whole day reproduces the weekday total exactly. Same
envelope pass, same 14-day EWMA half-life, today excluded (a day that
has only reached noon reports every evening hour as rest). Floored at
0.1 and renormalized at BUILD time so every reader sees the same
numbers: a rest hour projects a tenth of a uniform hour, never zero,
which is what the occasional overnight autonomous run costs. Additive,
so `schema` stays 2; ccpace v0.4.0 implements the identical model and
`docs/api/state-dir.md` is the contract, down to REST_MULT_MAX = 0.25.

Read under one validation — 24 keys, each numeric in [0, 24], mean in
[0.9, 1.1], days_history >= 14 — and anything else walks flat. A bad
hour shape narrows no clause and silences nothing; only the weekday
guards take the walk's voice away.

The walk steps local hours now (<= 169 of them), because a rate that
changes at 08:00 cannot be integrated a day at a time. That also ends
the L1 blend at exactly 24h: day-sized steps let a blend starting
mid-day run to the end of the day holding now+24h, up to 47 hours of a
hot rate on a sentence claiming 24. On a calm 10%/day profile with a 40%
trailing day, `lands ~70%` where it used to be ~73%.

Surfaced in three places. The budget long form gains `~6 awake` — the
windows falling in hours you have actually burned in — shown only when
it cuts the calendar count, and `even` then divides by it, because a
ration you can only hit by not sleeping is not a ration; at zero awake
windows both clauses go and the landing stands alone. The surplus
feasibility check counts awake seconds per leg, so `~35% expires even at
full burn` replaces `spend it` on a night. `report` states the rhythm it
walks: the longest circular run of rest hours, three or more, else "no
rest learned". Row 2, the strip fold and the windows-ahead countdown are
untouched.

Dry warnings need no new words: the shaped walk moves the dry TIME out
of sleep by itself, which was the early-warning fix all along.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lroolle
lroolle merged commit 25bb841 into main Sep 1, 2026
1 check passed
@lroolle
lroolle deleted the feat/hour-profile branch September 1, 2026 06:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant