Skip to content

chore: align halo with the updated homebrew skills - #1002

Merged
eetu merged 4 commits into
mainfrom
chore/align-with-homebrew-skills
Jul 26, 2026
Merged

eetu merged 4 commits into
mainfrom
chore/align-with-homebrew-skills

Conversation

@eetu

@eetu eetu commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Audits halo against the current homebrew skills (halo-design, spa-frontend, sibling-app, ts-style, lint-format) and closes the drift. Four commits, each reviewable on its own — start with the second; the first is pure reflow.

chore: adopt the house .editorconfig and reflow to 100 columns

lint-format makes .editorconfig the cross-language source of truth for indentation and line width. Prettier reads max_line_length, so adding the file moves it off its bare 80-column default and 37 files reflow. No behaviour change — skim it and move on.

feat(frontend): align with halo-design + spa-frontend

Tokens. themes.ts had drifted from the canonical colors_and_type.css. Two of these are live bugs the canonical file names explicitly:

token was now
light text.muted #a0a0a0 (~2.6:1 on white, fails AA) #767676
dark border #1f1f1f (invisible between #0f0f0f body and #1c1c1c/#252525 surfaces) #3a3a3a
dark text.main / muted / light #d6d6d6 / #8a8a8a / #646464 #ededed / #9c9c9c / #6f6f6f
dark error pink #ff8a8a
dark activity.offBackground #404040 #4a4a4a
onAccent — #1a1a1a (white on the accent is ~2.4:1)

Plus radiusPill, cardPadding, and the motion durations.

Touch. touch-action: manipulation on buttons/labels/summary — iOS double-tap-to-zoom misfires on quick repeated taps, which is exactly how a wall panel gets used.

Installable. Web manifest, full icon set, scripts/gen-icons.sh to regenerate from favicon.svg, per-scheme theme-color, viewport-fit=cover. Icons are full-bleed squares on the light body colour — the OS does its own rounding, and halo's #525252 ring is invisible on the template's dark ground.

iOS full-height. #root becomes the scroll container and pads off env(safe-area-inset-*); height is 100vh when installed vs 100dvh in a tab. iOS resolves 100dvh short at cold start in a standalone PWA and leaves a dead band until you rotate the device.

Stale-tab guard. Frontend and backend ship in one image, so a deploy replaces both and a panel left running serves a stale bundle. A Vite plugin emits version.json from the baked VITE_HALO_IMAGE_TAG; useDeployReload polls it and reloads on change. Keyed off the image tag, not a semver — a :main rebuild never bumps a semver.

chore: align repo tooling with sibling-app

Corepack is gone: yarn was already vendored and pinned by yarnPath, so CI and the Dockerfile now call it through node. This would have broken on the next node bump (node 25+ ships no bundled corepack), and the Dockerfile needed it on the build step too, not just install.

CI reads node-version-file: frontend/.node-version instead of a hardcoded "24" — a literal silently drifts, since dependabot bumps the Dockerfile node stage but can't touch a workflow literal.

Rust checks widen to the house flags in CI and the pre-commit hook; CI gained the missing typecheck. New: cve-scan.yaml (weekly trivy, SARIF to the Security tab, report-only, SHAs resolved fresh), SECURITY.md, a root justfile whose just dev runs both halves under one Ctrl-C, and [jobs.check] + background in bacon.toml. dependabot gains the docker ecosystem. The frontend package was still named vite_react_template.

docs: correct halo scope, routing and icon-migration claims

Mobile is no longer out of scope — the family default is touch-first and installable, and halo gets opened from phones. Also: there is no TanStack Router (App.tsx switches views from useState), and the lucide migration is in progress, not done — 5 files converted, ~12 still on Material Icons via components/Icon.tsx.

Verification

yarn validate clean, tests pass, cargo fmt/clippy clean with the new flags, podman build --target frontend-build succeeds without corepack. Computed styles in the built app confirm body 844px / overflow: hidden, #root scrolling and positioned, touch-action: manipulation on buttons, and the 100vh standalone rule present. Rendering checked at 1280×900 and 390×844.

The installed-PWA behaviour is the one thing not verified on hardware — the skill is explicit that the simulator doesn't reproduce the 100dvh cold-start bug. Worth adding halo to a phone home screen once this lands.

SECURITY.md documents halo's actual trust boundary: no app auth at all, and the only thing keeping that safe is that its public DNS record resolves to the LAN IP with no port forward, and its Traefik route is deliberately not in _gated_hosts.

Deliberately left out

  • The 43 React.FC components → named function declarations (ts-style)
  • Finishing the Material Icons → lucide migration
  • .node-version is still 24; bumping it now gets CI for free
  • dockerimage.yaml has no paths-filter gate and still tags latest on every main push — safe (the Pi pulls :main) but deploy-adjacent, so not changed blind
  • frontend/e2e-tests/ not renamed to e2e/; automerge.yaml still inline gh pr merge
  • yarn format still only covers src/, so the config files aren't Prettier-checked

eetu added 4 commits July 26, 2026 11:28
coding-style:lint-format makes .editorconfig the cross-language source of
truth for indentation and line width. Adding it moves Prettier off its bare
80-column default (it reads max_line_length), so every touched file reflows.

Pure formatting — no behaviour change. The hand-written changes ride in the
following commits.
Design tokens (themes.ts) had drifted from the canonical colors_and_type.css:

- light text.muted #a0a0a0 -> #767676. The old value is ~2.6:1 on white and
  fails AA; the canonical file calls it out by name.
- dark theme brightened: text.main #ededed, muted #9c9c9c, light #6f6f6f.
- dark border #1f1f1f -> #3a3a3a. #1f1f1f sat between the body (#0f0f0f) and
  the surfaces (#1c1c1c/#252525), so dividers and outlined controls vanished.
- dark error pink -> #ff8a8a, dark offBackground #404040 -> #4a4a4a.
- new onAccent (#1a1a1a) for text on an accent fill (white is ~2.4:1 on it),
  plus radiusPill, cardPadding and the motion durations.

touch-action: manipulation on buttons/labels/summary — kills iOS
double-tap-to-zoom, which misfires on quick repeated taps (brightness
steppers, view tabs) on a wall panel.

Installable PWA: web manifest, the full icon set + scripts/gen-icons.sh to
regenerate it from favicon.svg, per-scheme theme-color, and viewport-fit=cover.
Icons are full-bleed squares on the light body colour — the OS does its own
rounding, and the #525252 ring is invisible on a dark ground.

iOS full-height: #root becomes the scroll container and pads off
env(safe-area-inset-*), and height is 100vh when installed (html.standalone,
set in main.tsx) vs 100dvh in a tab. iOS resolves 100dvh short at cold start
in a standalone PWA, leaving a dead band until the device is rotated.

Stale-tab guard: frontend and backend ship in one image, so a deploy replaces
both and a panel left running serves a stale bundle. A Vite plugin emits
version.json holding the baked VITE_HALO_IMAGE_TAG; useDeployReload polls it
and reloads on change. Keyed off the image tag, not a semver — a :main
rebuild never bumps a semver.
Drop corepack. Yarn is already vendored at .yarn/releases and pinned by
yarnPath, so CI and the Dockerfile now invoke it through node. node 25+ ships
no bundled corepack, so the old `corepack enable` would have broken on the next
node bump — and the Dockerfile needed it on the build step too, not just the
install.

CI reads node-version-file: frontend/.node-version instead of a hardcoded "24".
A literal silently drifts: dependabot bumps the Dockerfile node stage but
cannot touch a workflow literal or .node-version.

Rust checks widen to the house flags in CI and the pre-commit hook
(cargo fmt --all, clippy --workspace --all-targets, test/build --workspace);
CI also gained the missing typecheck step.

New: cve-scan.yaml (weekly trivy of the :main image, SARIF to the Security tab,
report-only; action SHAs resolved fresh), SECURITY.md, a root justfile with a
`just dev` that runs both halves and tears them down on one Ctrl-C, and
[jobs.check] + background in bacon.toml for the headless dev flow.

dependabot gains the docker ecosystem (default-days only — the semver-* keys
break parsing for docker and github-actions).

The frontend package was still named vite_react_template; renaming it rewrites
its workspace entry in yarn.lock.
Mobile is no longer out of scope. The family default is that every app is
touch-first and installable; only a deliberately desktop-only app opts out, and
halo is a touch panel that also gets opened from phones. Documents the PWA and
stale-tab invariants that now back that up, plus `just dev`.

The layout section claimed TanStack Router (file-based). There is no router —
App.tsx switches views from useState.

halo-app-design claimed the lucide migration was done. It is not: 5 files use
lucide-react, ~12 still render Material Icons through components/Icon.tsx and
index.html still loads both Material stylesheets. Say so, and say new code uses
lucide.
@eetu
eetu merged commit bd41d42 into main Jul 26, 2026
3 checks passed
@eetu
eetu deleted the chore/align-with-homebrew-skills branch July 26, 2026 08:38
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