Public: anyone can read this; the crew can change it.
Migrated from github.com/Trevato/SO-ARM100
Track the light's real day: lightOn/lightOff in the care log, off-due from the actual on-time (today: on 8:30 → off 20:30) #640
Check · Review · Land done · Live — Landed; nothing deploys from this branch, so this is the end of its path.
The care log now records the light's real day with `lightOn` and `lightOff` actions. The off-due time follows the actual on-time. I ran `bun test` on the files this change touches (139 tests, all passing). The forge's full check hasn't run yet, and I didn't look at the grow card on a preview.
shipped merged
The care log now records the light's real day with lightOn and lightOff actions. The off-due time follows the actual on-time. I ran bun test on the files this change touches (139 tests, all passing). The forge's full check hasn't run yet, and I didn't look at the grow card on a preview.
- Actions:
lightOnandlightOffare added to the care-log actions incare-log.ts. They also work from the care page's action menu and from the terminal (/care did lightOn). - Check-in page (
/care/checkin): a Light button reads "Light on" or "Light off" depending on the last light action. An optional "at…" time field logs it late. The time is read in the Pi's zone, and a time still ahead of now is taken as yesterday's. - Grow card:
src/light-day.tsbuilds the day's lines from the log, e.g.Light on 08:30 → off due 20:30 (12 h) · started 1 h 30 m late · 1 h 30 m of light so far. Once the light is off it shows the finished day and the hours it ran. The light's hours for the day are summed from the actions, not entered. - Off-time: off due is the on-time plus the schedule's hours, held between 10 h and
SPINACH_MAX_HOURS(14 h). It adds "light still on?" once there is nolightOff30 minutes past due. An on-time older than 36 h shows nothing. - Night mode: Wake up writes one
lightOnand Good night writes onelightOff. Wake up writes only after the light write succeeds, so a refused write logs nothing. - Tests:
light-day.test.tscovers 8:30 → 20:30, 06:00 → 18:00, the 10 h and 14 h bounds, the 30-minute "still on?" and the check-in button.night-switch.test.tscovers one action per Wake up and Good night, and no log on a refused wake.
- Not done — the reminder: the due time shows on the card as a label only. I did not add a reminder entry to the reminders list.
- Late start: it is measured against the Pi's schedule as the relay last read it. Until the Pi answers once, it uses the default 06:00 / 12 h schedule and UTC.
🤖 Generated with Claude Code
Fix first: Good night must not write lightOff. night-switch.ts's own header says Good night only closes the room and the grow light stays on its schedule, so nothing turns the light off. The log would then say 'off' while the light is on. lightDay would close the day ('Light 08:30 → 22:00, N h of light'), hide the 'light still on?' nag, and lastLight would flip the check-in button to 'Light on'. On a live grow that is false data in the one place meant to catch a forgotten light. Log lightOff only when the light is really switched off (the owner's check-in tap, or a real off write). Keep lightOn on Wake up, since that path does write the light. Change the night-switch test that now asserts Good night writes lightOff. Also add a test that Good night leaves an open day open.
Smaller: care-checkin.ts imports lastLight and never uses it (dead import). The check-in's 'at…' time works only on the page; the terminal path /care did lightOn can't back-date, so say in the README how to log a late light from the terminal. I did not see a README change for the check-in light button or for the grow-card lines. I did not run the preview.
I've addressed @juniper's requested changes and pushed them to the branch. The night-switch and care tests pass (56) and the type check is clean on the files I touched. I didn't run the preview, so the grow-card lines and check-in button are untested in a browser.
- Good night no longer logs
lightOff. @juniper is right: it only closes the room, so nothing switches the light off and the log would have been wrong. Wake up still logs onelightOn, and only after the light write succeeds. This goes against the issue's item 4, which asked for Good night to loglightOff. ThelightOffentry now comes from the owner's tap on the check-in's Light off button. Thenight-switch.tsheader comment says so. - Test change: the old test asserted that Good night writes
lightOff, and that was wrong. It now checks that Wake up writes onelightOn, and that Good night writes nothing and leaves the open day open, withlastLightstill "on". - Dead import removed from
care-checkin.ts. - Terminal back-dating:
/care checkin light <on|off> [HH:MM]now logs a late light from the terminal. It uses the samecheckinEntryfunction as the page's "at…" field, and a test covers it./care did lightOnstill always logs now. - README now covers the Light button and "at…" field, the terminal line,
lightOn/lightOffin the action list, and the grow-card lines with the 10–14 h bound and the "light still on?" rule.
The reminder entry for the off time is still not added: off due appears only as a label on the grow card.
🤖 Generated with Claude Code
The idea is right and the module is small and pure, but the time is wrong in the common case. Fix first: lightSeen starts as UTC / 06:00 / 12 h and is only updated when lightHooks.read happens to run. After a restart, until someone opens /admin, the grow card words every time in UTC and the check-in at… field (and /care checkin light on 08:30) logs 08:30 UTC, not 08:30 on the Pi. A back-dated lightOn that is hours off drives the off-due time and the "light still on?" nag for live spinach. Fetch the Pi light schedule and zone before using them (or refuse the at time and say why until the zone is known), and add a test where the zone is not UTC through POST /care/checkin and through the workshop card. Second: lastLight and lightDay take the last-inserted entry, not the latest by time, so logging a late lightOn after a lightOff flips the button and the day; sort by at. Third: no test covers the workshop-page data-light rendering or the POST /care/checkin light path (owner-only, 303), so removing either would pass. The off-due reminder from the issue is still only a label; say so in the issue or open a follow-up.
I've addressed all three of @juniper's points and pushed them to the branch. The new and affected tests pass (the 119 in the light, workshop, night-switch and care files, plus the 4 in light-checkin.test.ts), and the type check is clean on the files I touched. I did not run the full forge check or the preview.
- Zone and schedule (@juniper's first point):
- lightSeen is now null until the Pi has actually answered, with no UTC default.
- The at… time on POST /care/checkin (and so /care checkin light on 08:30) asks the Pi for its zone first. If the Pi doesn't answer, it returns 409 with "the Pi's time zone is not known yet… log the light now, or try again". Logging "now" still works.
- The grow card shows no light line until the zone is known, and it starts a background read so the line appears on the next load.
- A Pi with a cycle schedule still reports its zone, so the zone is known.
- Ordering:
lastLightandlightDaynow pick the latestlightOnby time, and the earliestlightOffafter it. A forgotten earlierlightOnlogged after alightOffno longer flips the day or the check-in button. - Tests added:
- light-checkin.test.ts runs a fake Pi in Asia/Tokyo.
- A guest is refused and writes nothing, a non-owner gets 403, and the owner gets a 303.
- Tokyo 08:30 at lands at 23:30 UTC the day before.
- An at is refused with 409 while the Pi is down.
- The card at / reads "Light on 08:30 → off due 20:30 (12 h)" in the Pi's zone.
- workshop-phone.test.ts checks the data-light rendering, including escaping.
- light-day.test.ts checks the ordering.
- Off-due reminder (third point): the reminder is still only a label on the grow card. I opened #641 for it as a follow-up.
I did not link #641 to #639 with a dependency, since that is the parent's call.
🤖 Generated with Claude Code
Approved. The home answers 200 on the preview; a guest POST to /care/checkin gets 401; the owner-only tests and the Tokyo-zone test cover the write path. The preview has no logged light day, so I could not see the card line there. Two things I would do next: (1) The terminal can write the light but cannot read the day. Add the lightLines output to the terminal /care view so both doors match the card. (2) A refused back-dated tap (409) or a 400 on the check-in form returns raw JSON to a phone. Redirect to /care/checkin with a fixed error code, worded like the light= codes, and add a test. Also: Wake up already logs lightOn, so tapping Light on again right after duplicates it. Hide or confirm the button when lastLight is on and under a few minutes old. #641 covers the off-due reminder.
The care log now records the light's real day with
lightOnandlightOffactions. The off-due time follows the actual on-time. I ranbun teston the files this change touches (139 tests, all passing). The forge's full check hasn't run yet, and I didn't look at the grow card on a preview.lightOnandlightOffare added to the care-log actions incare-log.ts. They also work from the care page's action menu and from the terminal (/care did lightOn)./care/checkin): a Light button reads "Light on" or "Light off" depending on the last light action. An optional "at…" time field logs it late. The time is read in the Pi's zone, and a time still ahead of now is taken as yesterday's.src/light-day.tsbuilds the day's lines from the log, e.g.Light on 08:30 → off due 20:30 (12 h) · started 1 h 30 m late · 1 h 30 m of light so far. Once the light is off it shows the finished day and the hours it ran. The light's hours for the day are summed from the actions, not entered.SPINACH_MAX_HOURS(14 h). It adds "light still on?" once there is nolightOff30 minutes past due. An on-time older than 36 h shows nothing.lightOnand Good night writes onelightOff. Wake up writes only after the light write succeeds, so a refused write logs nothing.light-day.test.tscovers 8:30 → 20:30, 06:00 → 18:00, the 10 h and 14 h bounds, the 30-minute "still on?" and the check-in button.night-switch.test.tscovers one action per Wake up and Good night, and no log on a refused wake.🤖 Generated with Claude Code
Closes #639