Skip to content

feat: prepare Night Walker for friend distribution - #1

Closed
ItsFlow wants to merge 5 commits into
mainfrom
fm/cfs-prodready
Closed

feat: prepare Night Walker for friend distribution#1
ItsFlow wants to merge 5 commits into
mainfrom
fm/cfs-prodready

Conversation

@ItsFlow

@ItsFlow ItsFlow commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Intent

Make Night Walker production-ready for friend distribution, then ship a green PR via no-mistakes against the existing public repo https://github.com/ItsFlow/night-walker (do not create another repository). Branch fm/cfs-prodready. Firstmate owns merge.

Product name is Night Walker. Keep executable/package name color-filter-scheduler. Keep bundle id com.flo.color-filter-scheduler (historical; changing it would orphan the captain's prefs and login item). User-facing name, DMG, README, and menu-bar panel title are Night Walker.

Hard safety on the captain's live Mac: do not install over ~/Applications/Color Filter Scheduler.app, rewrite the LaunchAgent, or write com.flo.color-filter-scheduler UserDefaults. Do not leave Color Filters changed. Negative lat/lon cannot be passed via NSArgumentDomain. Do not change MediaAccessibility SPI signatures (CMediaAccessibility.h), solar math formula, or persisted config keys. CLT only, no Xcode, no third-party deps. Do not notarize or request Apple Developer credentials; ad-hoc sign and document Gatekeeper.

Ship: security + stability tests that actually run (solar fixtures, polar day/night, longitude-near-UTC-day-boundary, reconcile/decide, CLI read-only vs mutate-with-restore, bundle codesign, universal lipo, repo hygiene) via tests/run.sh; security hardening without inventing a TCC helper or notarization flow; honest residual risk (ad-hoc signature, private Color Filters SPI, not App Store); universal .app via bundle.sh and friend-ready dist/NightWalker-.dmg; GitHub Actions on macos-latest (skip GUI-only steps). Do not open a GitHub Release until CI is green.

Captain 2026-08-19: never launch Claude. For any review or no-mistakes pipeline agent use Codex only. Do not spend Claude quota.

Delivery is no-mistakes to a green PR against origin main. Do not merge. Do not push to the default branch.

What Changed

  • Rebrand the user-facing app as Night Walker and add universal, ad-hoc-signed app and DMG packaging for Intel and Apple Silicon.
  • Replace the legacy LaunchAgent flow with SMAppService login-item registration, plus guarded install and uninstall behavior.
  • Harden CLI and scheduler validation and add a state-restoring test suite with packaging, hygiene, UI contract, and macOS CI coverage.

Risk Assessment

⚠️ Medium: The login-item fix is coherent and removes the competing LaunchAgent owner, but the change remains broad and distribution-sensitive, with documented residual risk from ad-hoc signing and private MediaAccessibility SPI.

Testing

Targeted debug, scheduler, safety, rendered-UI, universal bundle, codesign, and mounted-DMG checks all passed; reviewer-visible evidence was captured externally, live Color Filters remained unchanged, and generated worktree artifacts were cleaned up.

  • Evidence: Running Night Walker panel (local file: /var/folders/16/p22jkpcn0z10z3lrwkpc4yq00000gn/T/no-mistakes-evidence/01M0E3GXTNQJ55PW3M74JBRENA/panel-front-running.png)
  • Evidence: Night Walker settings panel (local file: /var/folders/16/p22jkpcn0z10z3lrwkpc4yq00000gn/T/no-mistakes-evidence/01M0E3GXTNQJ55PW3M74JBRENA/panel-settings.png)
Evidence: Scheduling and live-state safety transcript
Night Walker scheduling CLI evidence

now: 2026-08-18 13:00:00 +01:00
sunrise: 2026-08-18 05:11:56 +01:00
sunset:  2026-08-18 19:23:36 +01:00
decision: between sunrise and sunset — light -> want OFF
now: 2026-08-18 23:15:00 +01:00
sunrise: 2026-08-18 05:11:56 +01:00
sunset:  2026-08-18 19:23:36 +01:00
decision: after sunset — dark -> want ON
now: 2026-06-21 13:00:00 +01:00
sun never sets today (polar day)
decision: polar day (sun never sets) — treating as light -> want OFF
now: 2026-12-21 12:00:00 Z
sun never rises today (polar night)
decision: polar night (sun never rises) — treating as dark -> want ON
now: 2026-08-18 16:30:00 +01:00
sunrise: 2026-08-18 21:03:03 +01:00
sunset:  2026-08-19 10:27:37 +01:00
decision: before sunrise — dark -> want ON

Color Filters before: enabled=0 intensity=1 type=16
Color Filters after read-only decisions: enabled=0 intensity=1 type=16
Evidence: Mounted DMG inspection
DMG: dist/NightWalker-1.0.0.dmg
Format Description: UDIF read-only compressed (zlib)
	Total Bytes: 12249600
Mounted contents:
.build/dmg-mount.jOXcpQ/Night Walker.app
.build/dmg-mount.jOXcpQ/Applications
Night Walker
com.flo.color-filter-scheduler
Architectures in the fat file: .build/dmg-mount.jOXcpQ/Night Walker.app/Contents/MacOS/color-filter-scheduler are: x86_64 arm64 
.build/dmg-mount.jOXcpQ/Night Walker.app: valid on disk
.build/dmg-mount.jOXcpQ/Night Walker.app: satisfies its Designated Requirement
Evidence: Universal bundle contract
==> Building universal release (arm64 + x86_64)…
[0/1] Planning build
Building for production...
[0/3] Write sources
[1/3] Write swift-version--1AB21518FC5DEDBE.txt
[3/4] Compiling color_filter_scheduler AppDelegate.swift
[3/5] Write Objects.LinkFileList
[4/5] Linking color-filter-scheduler
Build complete! (3.64s)
[0/1] Planning build
Building for production...
[0/3] Write sources
[1/3] Write swift-version--1AB21518FC5DEDBE.txt
[3/4] Compiling color_filter_scheduler AppDelegate.swift
[3/5] Write Objects.LinkFileList
[4/5] Linking color-filter-scheduler
Build complete! (3.26s)
==> Assembling /Users/flo/.no-mistakes/worktrees/4584634a42b3/01M0E3GXTNQJ55PW3M74JBRENA/dist/Night Walker.app
==> lipo /Users/flo/.no-mistakes/worktrees/4584634a42b3/01M0E3GXTNQJ55PW3M74JBRENA/.build/arm64-apple-macosx/release/color-filter-scheduler + /Users/flo/.no-mistakes/worktrees/4584634a42b3/01M0E3GXTNQJ55PW3M74JBRENA/.build/x86_64-apple-macosx/release/color-filter-scheduler
Architectures in the fat file: /Users/flo/.no-mistakes/worktrees/4584634a42b3/01M0E3GXTNQJ55PW3M74JBRENA/dist/Night Walker.app/Contents/MacOS/color-filter-scheduler are: x86_64 arm64 
==> Rendering app icon (.icns)
wrote iconset -> /var/folders/16/p22jkpcn0z10z3lrwkpc4yq00000gn/T/tmp.euE0v4GgnN/AppIcon.iconset
==> Ad-hoc signing

Built: /Users/flo/.no-mistakes/worktrees/4584634a42b3/01M0E3GXTNQJ55PW3M74JBRENA/dist/Night Walker.app
Run it directly with:  open "/Users/flo/.no-mistakes/worktrees/4584634a42b3/01M0E3GXTNQJ55PW3M74JBRENA/dist/Night Walker.app"
bundle-contract: inspecting dist/Night Walker.app
ok: codesign --verify
ok: codesign identifier is com.flo.color-filter-scheduler
ok: Info.plist CFBundleIdentifier is com.flo.color-filter-scheduler
note: Architectures in the fat file: dist/Night Walker.app/Contents/MacOS/color-filter-scheduler are: x86_64 arm64 
ok: universal binary (x86_64 + arm64)
ok: executable links ServiceManagement for launch at login
bundle-contract: all checks passed

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed (3) ✅
  • 🚨 tests/ui-contract.sh:45 - The newly added panel-title checks only grep Swift source, so they can pass for dead/commented text and violate the explicit test-quality rule. The surrounding panel-contract test uses the same source-content-only pattern. Replace these with observable UI/public-interface checks or remove them; similarly, bundle-contract.sh should require both architectures directly from lipo output instead of deciding whether universality is required by grepping bundle.sh.

🔧 Fix: Replace source-grep contracts with runtime checks
2 errors still open:

  • 🚨 tests/cli-contract.sh:221 - The required “CLI read-only vs mutate-with-restore” test does not actually run on a clean machine: when the original Color Filters preferences are absent—as expected on GitHub-hosted runners—the successful --set-enabled and --reconcile --apply paths are skipped and the suite still passes. Decide whether this acceptance criterion must run in CI or is explicitly allowed to be a captain-only conditional test; if it must run, provide a recoverable isolated mutation strategy that restores the initially absent state.
  • 🚨 README.md:23 - The friend installation flow only copies the app from the DMG and never registers it to launch at login. After logout or reboot, the menu-bar process—and therefore its five-minute/wake reconciliation—will not run until the friend manually opens it again, despite the instructions presenting Automatic as an ongoing sunset/sunrise scheduler. Confirm whether friends are expected to reopen it each session; otherwise add a supported login-item flow (or explicit Login Items setup instructions) at the distribution boundary.

🔧 Fix: Register Night Walker as login item
1 error still open:

  • 🚨 Sources/color-filter-scheduler/AppDelegate.swift:71 - Two launch-at-login owners now compete: install.sh starts the bundled executable through a LaunchAgent, then this startup path also registers SMAppService.mainApp. If registration succeeds, subsequent logins can launch two app processes, producing duplicate menu items and competing reconciliation. Choose one mechanism at the shared installation boundary—preferably migrate install.sh to SMAppService—or explicitly detect the managed LaunchAgent before registering.

🔧 Fix: Unify login lifecycle under SMAppService
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • swift build
  • .build/.../color-filter-scheduler --selftest
  • Deterministic --decide --now ... checks for Munich daylight/darkness, 80°N polar day/night, and Tokyo near the UTC-day boundary
  • Compared live Color Filter enabled, intensity, and type values before and after read-only CLI decisions
  • .build/.../color-filter-scheduler --render-panel .build/panel-evidence-$PPID; visually inspected running and settings PNGs
  • bash tests/bundle-contract.sh
  • ./dmg.sh
  • Mounted dist/NightWalker-1.0.0.dmg read-only and inspected its app name, Applications link, bundle identifier, x86_64/arm64 executable, and code signature
  • Detached the DMG and removed all generated worktree packaging/render artifacts
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Flo added 5 commits August 19, 2026 23:49
Public name is Night Walker; bundle id stays com.flo.color-filter-scheduler
so the captain's prefs and login item are not orphaned.

Packaging: bundle.sh now lipo-creates a universal ad-hoc-signed
dist/Night Walker.app; dmg.sh writes dist/NightWalker-<version>.dmg.
install.sh/uninstall.sh target Night Walker.app and refuse to hijack a
side-by-side Color Filter Scheduler.app.

Security: CLI fail-closed on NaN/Inf/out-of-range coords and intensity;
--render-panel stays under cwd (symlinks resolved) and does not write
Settings; LaunchAgent paths go through PlistBuddy.

Tests: tests/run.sh is the single local/CI entry (solar fixtures,
--decide/--selftest, CLI restore, hygiene, bundle/codesign). GitHub
Actions runs the headless suite on macos-latest.

Proof: RUN_BUNDLE=0 tests/run.sh exit 0; bundle-contract lipo x86_64+arm64
and codesign --verify; Color Filters and captain prefs restored exactly.
@ItsFlow ItsFlow closed this Aug 20, 2026
@ItsFlow
ItsFlow deleted the fm/cfs-prodready branch August 20, 2026 13:45
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