Skip to content

feat(home): show the week from the time service - #155

Merged
Bakhomious merged 1 commit into
mainfrom
step/home-time-week
Oct 29, 2026
Merged

Bakhomious merged 1 commit into
mainfrom
step/home-time-week

Conversation

@Bakhomious

Copy link
Copy Markdown
Contributor

Brief

Goal. The Home's "This week" shows the real week. Home asks the time service for it over the time contract (bakhyard.time.v1, #154) and answers it, with how asking went, so that the app can tell a time service that's down from one that isn't there (decision 186).

Scope.

  • A new package of home's, week: an Asker that asks the peer named time in home's BAKHYARD_PEERS for TimeService/GetWeek, over gRPC on h2c, with 1.5 s to answer, as each peer has for its items. It returns the week, or none when time has none, and how asking went: ok, or unavailable when the call fails. A failure is logged get the week with peer=time, unless the request has ended. Without a time peer, it asks nothing.
  • screen: a Week type, and the Home's week and weekState.
  • api: Register takes the two asks as api.Peers, and makes both at once.
  • main.go wires it, with a test against a stand-in time.
  • process-compose: home's BAKHYARD_PEERS names time.
  • Docs: plan §0, §4.11, §8.2 and decision 186. home-time-week splits in two, so time-tracking has fourteen steps.

Out of scope.

  • The Home saying "Hours unavailable": the next step, week-unavailable. The app is unchanged: it shows week when the answer has one, as it did with the demo week, and ignores weekState.
  • The homelab repo: the laptop's home already names time, and a NetworkPolicy lets it reach time (codedogapp/homelab#42).
  • Time's items for "Needs you today" (time-attention).

Acceptance criteria.

  1. With a time peer that answers a week, GET /home answers "week":{"loggedHours":…,"targetHours":…} and "weekState":"ok".
  2. With a time peer that answers no week, as without Jira, there's no week, and "weekState":"ok".
  3. With a time peer that fails, such as with UNAVAILABLE before its first read of the worklogs, or is down, or doesn't answer within 1.5 s, or answers hours that aren't finite, which JSON can't encode: no week, "weekState":"unavailable", and get the week logged with peer=time, unless the client has gone.
  4. Without a time peer, the answer has neither week nor weekState, and nothing is asked.
  5. Home asks for the week and the items at once: the answer waits for the slower of the two, not for both in turn.
  6. A week with nothing logged answers "loggedHours":0, a week rather than none.
  7. process-compose's home names time.
  8. mise run check passes.

QA

  • Mutations: 45 of 45 caught (mutate.py, with go test -race ./services/home/...):
    • week.go: no timeout, a longer or a shorter one; no client check; a state without time; no log, a log after the client has gone, the call's context checked, another message, no peer in the log; ok on a failure; unavailable without a week; the HasWeek check removed or inverted; either hours dropped, swapped or read twice, a target of 40; the finite check removed, joined with &&, on one value only, NaN taken as finite, one infinity only; ok, or no log, on hours that aren't finite; the first peer asked; no peer check; another peer name; Connect's protocol; HTTP/1.1;
    • api.go: the week asked before the items, the wait before them, no wait, the week or the state left out, the request's context dropped;
    • screen: a null week, an empty weekState, another member name;
    • main.go: not wired; wired without the peers.
    • "Not wired" first didn't build, since it left a variable unused; the mutant now drops the asker too.
  • Live (live.py, 44 checks, all passed, run again after the review's fix): home and time built from the branch, on the loopback, with a stand-in Jira.
    • AC3: time down: unavailable at once, logged with peer=time and the refused connection.
    • AC2: time without Jira, started after home: ok, no week.
    • AC1: with Jira, 1.5 of 40 hours and ok, the same week as time's GET /time/report.
    • AC6: nothing logged: {"loggedHours":0,"targetHours":40}.
    • AC3: Jira refusing: unavailable, logged with time's reason, "no read of the worklogs on Jira has succeeded yet".
    • AC3, AC5: a first read that takes 3 s: home answers in 1.45 to 2.2 s with unavailable and logs deadline_exceeded, and the items aren't held up; once the read is in, ok with the week.
    • AC3: a client that leaves after 0.5 s: nothing logged. A QA build without the request's check (go build -overlay) logs canceled there, so the check isn't vacuous.
    • AC4: no peer named time (time named pulls instead): neither member, nothing logged.
    • AC7: the stack from process-compose.yaml: home's peers name time at time's address, and GET /api/home through the gateway answers "weekState":"ok" and no week, since Jira is off in the dev settings. A copy of the compose file without time in home's peers is caught.
    • Each process stops on SIGTERM with exit 0.
  • Shots spec (shots.spec.ts, 8 checks, all passed): the demo Home with "weekState":"ok" shows its week; an unavailable week leaves "This week" out, with no console problem; a week with nothing logged shows "0h / 40h".

Review

One blocking finding, fixed:

  • JSON can't encode NaN or an infinity. A week with such hours made json/v2 stop mid-answer: home sent a 200 with a body cut short, {"name":"Alex", and the whole Home failed to load, where §4.11 says a failing peer never blanks the screen. Time never sends them, since it sums durations, but the contract allows any double. Home now counts such hours as a failure: unavailable, logged as get the week with hours that aren't finite: NaN of 40. Three test rows and ten mutants cover it; §4.11 and decision 186 say so.

Non-blocking:

  • The h2c client's setup is repeated in feed and week, four lines, under dupl's threshold.
  • The api tests' listing helper became nothing, since unparam flagged a parameter that every caller left empty.
  • Time stays one of the Home's sources, as an attention peer whose contract it doesn't serve yet, until time-attention.
  • The home main package's coverage is 64.3%: main.go's wiring, which the gate leaves out; main_test.go covers the routes end to end against a stand-in time.
  • Found in review, older than this step: a peer's due time outside the years 0 to 9999 cuts the Home's answer short the same way. It's an idea in §0.

Shots

The demo Home, with the week from the answer: "31h 30m / 40h".

The Home on a desktop, light
The Home on a desktop, dark
The Home on a phone, light
The Home on a phone, dark

Gates

mise run check passed locally after the fix:

  • Go fmt; golangci-lint (0 issues); buf lint and format; jactionlint; process-compose dry run; gen:check; govulncheck (none);
  • Go tests with -race, Go coverage 96.0% total (services/home/internal/week 100%);
  • Biome, svelte-check, tsc, knip, pnpm audit;
  • Vitest, 1,102 tests;
  • Playwright E2E, 337 passed and 7 skipped.

SonarQube Cloud runs on demand (decision 132).

Merged under the user's standing OK (2026-10-26): merge once CI's check is green, and review everything at the end.

Home asks the time service for this week's hours over the time
contract, at the same time as the peers' items and with the same
1.5 s, and answers them as the Home's week beside a new weekState, so
the app can tell a failing time service from one without a week
(decision 186). Hours that JSON can't encode count as a failure, so
they can't cut the Home's answer short.
@Bakhomious
Bakhomious merged commit 4739f4e into main Oct 29, 2026
2 checks passed
@Bakhomious
Bakhomious deleted the step/home-time-week branch October 29, 2026 16:45
Bakhomious added a commit that referenced this pull request Oct 29, 2026
Since #155, home's answer says how asking the time service for the week
went. When home couldn't get the week, the Home left "This week" out, as
if Jira weren't set up. It now keeps the section's head and link, and the
week card says "Hours unavailable" in the hours' type, muted, without
the label and the bar (decision 187).
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