Commit Graph
6 Commits
Author SHA1 Message Date
iris a50d72960c Say how long is left, not that the window is five hours
The bar read "31% of 5h", which is the one thing about the window a
reader already knows. What decides whether to start something now is how
long what is left has to last: 80% with twenty minutes to go and 80%
with four hours to go are opposite answers, and the second number was a
screen away on the usage screen.

It now reads "31% - 2h 36m left", and the countdown is driven by a clock
the refresh loop advances rather than computed at draw time. A
percentage that comes back unchanged is an equal value, so Compose skips
the recomposition -- a "left" recomputed only when the quota happens to
move would have sat at a stale figure for hours while looking live.

A window can arrive with no reset time, so that keeps its own wording:
"reset time unknown" rather than "refresh soon", which would be a
recommendation nothing measured. Under a minute, including past the end,
is "refresh soon" -- "0m left" reads as a measurement.

The span arithmetic was already on the usage screen, so it moves into
`ResetCountdown.kt` and both callers supply their own sentence. That
screen still reads "resets in 2h 37m" and "resets in 5d 21h", checked on
the emulator alongside the bar it was not part of changing.

The fill is blue rather than the scheme's primary: the bar sits under
every session header, on a screen somebody opened to do something else,
and it reports a quantity rather than a verdict. The usage screen is
still where the same number turns yellow and then red, for a reader who
went there to be told where the limits are.

Also declares this project's resources for Dev Updater, whose
declaration schema changed in d27b5a3: `resources.ron` says ai-app keeps
its state as `ai-app`, so the Uninstall dialog offers the real
directories instead of saying it cannot tell where they are. Only the
name, because both XDG places are the conventional ones. What that
dialog's config toggle would delete includes the CA under `certs`, which
strands every phone running an APK pinned to it -- noted where somebody
would be standing when it matters.
2026-08-29 20:54:55 -04:00
irisandClaude Opus 5 f842d0e512 Call the server component "server", to match dev-updater
READ BEFORE PULLING. A Managed component's service unit is named
<config key>-<component name>, so this rename moves the unit from
ai-app-backend to ai-app-server and nothing points at the old one
afterwards. Uninstall the backend component from its card *first*, while
it is still called "backend"; then pull, accept the new declaration --
.dev-updater.ron is a request, so the card shows it as pending -- and
build. The unit installs under the new name.

Two things reset rather than break, both keyed by component name: the
per-component built_from sha, and the build and runtime logs. One build
makes the sha current again.

Also drops the claim that the components list is walked in order. They
have built in parallel since 2026-08-28, so the reasoning the comment
gave -- backend first, so a failing APK leaves the phone what it had --
no longer describes what happens.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VETa8afmpWaYezLCqJhDB8
2026-08-29 15:40:31 -04:00
iris 3cf6925d90 Let Dev Updater supervise the backend, now that the switch can be sequenced
Re-applies the change reverted in d5a0f67. It was right then and only
mistimed: something was reading this working tree live, so deleting the
script took the backend card to "couldn't check" immediately rather than
on a pull. Iris has now uninstalled the service while the script was still
the declared one, which is the step that stops the old unit being orphaned
under a name nothing points at any more.

`Managed` runs the command with dev-updater's built-in service script,
resolved against the component's cwd. ai-app's own script was the generic
case exactly -- ExecStart=$BINARY with no arguments and no environment --
so it was 233 lines of init-system detection kept in step with an
identical copy next door.

Deleting it loses nothing, and that was checked rather than assumed: all
three findings the test guest produced today are in the built-in --
reading OpenRC's status exit code instead of grepping text it prints to
stderr, treating an uninitialised user softlevel as "couldn't find out"
rather than as stopped, and assigning through `|| code=$?` so `set -e`
cannot kill the script before it reads the code.

The one thing the script said that the built-in cannot is already in
AGENTS.md: Stop on this card takes down the server a phone reaches through
the tunnel, while Dev Updater itself is unaffected because it uses its own
port.

Install from the backend card after taking this.
2026-08-28 19:52:42 -04:00
iris d5a0f67a3a Put the service script back until the switch can be sequenced
Reverts the switch to `service: Managed(...)`. The switch is still right
and the reasoning in that commit still holds; what was wrong was doing it
now, unilaterally, to a checkout something is reading live.

A dev-updater is running against this working tree, so deleting
`server/service` did not wait for a pull to take effect -- the backend
card went to "couldn't check -- failed to run the service script: No such
file or directory" immediately, and the pushed declaration still names the
script, so the tree and the declaration disagreed in the one direction
that breaks things. My own commit message had said this change was not
safe to pull blind; it turned out not to need a pull at all.

The switch needs three steps in order, and only the middle one is mine:
Uninstall from the backend card while the script is still declared, then
take the change, then Install. Re-apply when Iris is ready to do that,
which is also when dev-updater's conversion path can be deleted.
2026-08-28 18:18:38 -04:00
iris c2dfaab349 Let Dev Updater supervise the backend instead of shipping a script
dev-updater now carries a built-in service implementation, generated from
a template and driven through the identical interface a project-supplied
script uses, so a project whose service is unremarkable no longer writes
one. ai-app's was unremarkable: `ExecStart=$BINARY` and `command="$BINARY"`
with no arguments and no environment. 233 lines of it, and the half that
matters most -- the OpenRC branch, which neither project can exercise from
a systemd machine -- existed twice, so a fix found by testing would have
had two places to land and no way to notice the second.

The field keeps its name; `Managed` takes the command, resolved against
the component's `cwd`.

The one thing the script said that the built-in cannot is kept, in
AGENTS.md rather than lost: Stop on this card takes down the server a
phone reaches through the tunnel, while Dev Updater itself is unaffected
because it uses its own port -- which is exactly what makes that button
easy to press and easy to regret.

NOT SAFE TO PULL BLIND. A managed service is named after the component, so
this one becomes `app-backend` while the installed one still has the name
the script gave it. Uninstall from the backend card *before* taking this
change, then Install after; pulling first orphans a service that stays
enabled and starts at boot with nothing pointing at it.
2026-08-28 17:35:27 -04:00
irisandClaude Opus 5 5f8a2146e6 Ask Dev Updater for the checkout, not for the app inside it
Dev Updater's unit is a project -- a directory in a checkout -- that
produces components, so this declaration belongs at the repository root
where it can say where each half lives. `cwd` is how a component says
that, and it is what the old file was working around: sitting in `app/`,
it reached the backend with `../server/Cargo.toml` and `../server/service`,
which described the layout backwards.

So the file says what this repository produces: the backend, built and
serviced in `server/`, and then the APK, built in `app/`. The order is
unchanged and still the point -- a failing APK build leaves the phone the
APK it already had rather than half of a matched pair.

The service script gains dev-updater's note about lingering. A user
service stops at logout unless `loginctl enable-linger` is set, which for
this one matters more than for a build server: the phone reaches ai-server
whether or not anyone is logged in at the desk.

**This changes the project path, so the phone's existing entry (at
~/repos/ai-app/app) has to be removed and the checkout root added
instead**, and its components accepted once.

Verified against dev-updater's current parser rather than by reading its
schema: the declaration loads, `cargo build --release` resolves into
server/, app/build-apk.sh into app/, the service script to an absolute
path, and APK discovery from the root still finds the built APK.
`./server/service status` prints not-installed and exits 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017xn8nHw1tw1R6PtiY1eEtw
2026-08-28 02:26:02 -04:00