aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* Merge origin/main: reconcile two parallel sessions' velox workCraig Jennings9 hours9-258/+3177
|\ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Both sides worked velox independently while this branch was open, so the overlaps needed settling by hand rather than by whichever side landed last. The settings-persistence bug had been recovered twice under different headings. Kept the upstream wording and dropped my duplicate — one bug, one task. The six tasks I archived had graduated from the Resolved section into archive/task-archive.org; upstream still listed them under Resolved. Removed them there so each lives in exactly one place. The ribbon task is the real disagreement. I verified on 08-15 that the reseat happened and the touchpad came back — the interrupt on amd_gpio pin 8 went from zero counts to 1795 and the i2c-HID reset timeout disappeared. The 08-17 entry concluded the opposite from the absence of a /dev/input/by-path/ node, which an i2c-HID touchpad often lacks even when working. Rather than close it over that entry, I left the task open and recorded both readings with the check that settles it, because velox was refusing ssh and I could not re-verify. Carried across my checks 6 and 7 on the post-rebuild task — the per-install Proton Bridge cert and password, neither of which can be restored from backup — and the restore-versus-re-derive split they belong to.
| * feat(post-rebuild-check): let a machine declare which units it means to ↵Craig Jennings13 hours2-1/+173
| | | | | | | | | | | | | | | | | | | | | | | | | | | | leave disabled Check 2 treats "enabled" as a proxy for "will actually run", and the proxy is wrong for a unit nobody intends to enable on that box. velox has four: geoclue-agent is redundant because hyprland's exec-once starts the binary itself, emacs is started on demand by emacsclient, obs-record-watchdog only matters while recording, and obsbot-wb-guard needs an OBSBOT the laptop doesn't have. All four reported at every run. Four permanent lines in front of every real finding teach me to skim the output, which is the argument check 4 already makes about CLAUDE.md. On velox this takes the run from 8 findings to 4. The list is machine-local, read from $XDG_CONFIG_HOME/post-rebuild-check/units-expected-disabled. It can't live in the unit file, because obsbot-wb-guard is correctly enabled on ratio. One unit, a different right answer per machine. An entry whose unit is enabled after all is reported too. The main loop can't catch that, since it skips any state that isn't disabled or linked, so the list gets its own pass. Without it a stale exemption sits there suppressing nothing, and the list becomes somewhere real findings go to die. The exemption is tested last, so it never hides the dangling-symlink finding decided on the filesystem above it.
| * fix(post-rebuild-check): stop overstating an unregistered signal accountCraig Jennings14 hours1-4/+6
| | | | | | | | | | | | The finding said agent-text relays into this machine, so a missing account broke paging for the whole fleet. That was true when the check was written and isn't now. agent-text walks AGENT_TEXT_RELAYS in order and skips itself, so a machine with no account pages through a relay that has one. It's still worth flagging, because the fleet does lose paging when no relay host is registered either. I reworded the finding to say that instead.
| * chore(tasks): record the clone decision and move the ribbon deadlineCraig Jennings19 hours1-1/+43
| | | | | | | | | | | | The shallow-clone task now records why I settled the remote-URL half as I did, and the two options I turned down. Without that written down I'll relitigate it the next time I look at the https default and think detection would be tidier. The personal-ISO half is noted on the secrets task that will carry it. The input-cover ribbon reseat moves to 2026-08-26. It needs the machine open on a bench and I'm away until then.
| * feat(post-rebuild-check): flag a stopped idle daemon and a read-only remoteCraig Jennings19 hours2-22/+315
| | | | | | | | | | | | | | | | | | | | Both are states where the machine looks finished and isn't, which is the whole point of this script. Check 7 asks whether hypridle is running. Nothing else notices when it isn't. Idle lock and suspend stop happening, and the laptop runs until its battery is gone. That's how velox reset its RTC on 2026-08-19, which is what dropped it into check 6's clock and DNS deadlock. The check asks whether the daemon is alive rather than why it might not be, so a crash and a stale caffeine surface alike. It's gated on hypridle being installed, since only Hyprland machines get it. Check 8 asks whether the working repos can push. The installer clones them from the read-only https endpoint. That's right for someone installing archsetup with no key on my server, and wrong for my own machines. Nothing about the tree shows it. velox's dotfiles remote sat that way for four days and announced itself as a 403. Only my own read-only endpoint is flagged. An https remote elsewhere may push fine through a credential helper, and guessing about hosts this machine doesn't own would stand noise in front of real findings.
| * fix(installer): clone my working repos with full historyCraig Jennings19 hours2-2/+163
| | | | | | | | | | | | | | | | | | | | archsetup and dotfiles were cloned with --depth 1. They aren't build trees. They're the two repos I develop in on every machine this installs, and velox came back from its rebuild carrying 7 commits of history in each instead of 851. A shallow clone degrades quietly. Past the graft point `git log -- <path>` answers "no commits" rather than failing, so a search of history for specific files came back empty and exited clean. The clone couldn't see the history they live in. Blame and bisect break the same way, less dangerously. Dropping --depth also drops the implicit --single-branch, so both clones now fetch every branch. That's what I want in a repo I work in. The AUR build clones stay shallow. They exist to run make install and are then discarded. A test asserts they keep --depth 1, so a broad sed can't take them along.
| * chore(tasks): archive the closed work and convert finished sub-tasksCraig Jennings28 hours2-210/+204
| | | | | | | | Routine cleanup. The net-scenarios timeout subtree moves to the archive now that it is closed, an aged clock-panel subtree goes with it, and finished sub-tasks are rewritten as dated log entries under their parents.
| * chore(tasks): claim the roam captures and record the scaling diagnosisCraig Jennings28 hours1-45/+174
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Four items claimed from the shared roam inbox: - Qt apps oversized on velox - function keys issuing media actions instead of F-keys - waybar panels launching expanded - a question about the analog clock avoiding being dragged The last is a VERIFY, since the capture asks for a conversation rather than describing a defect. Two unowned product links stay in the shared inbox. The Qt one is diagnosed and fixed in dotfiles ec8e9a8, recorded here with the measurement. A VERIFY rides along on whether the calibre DPI pin is still needed, because it looks like the same double-scaling worked around per-app. The cursor comment in that file records it a third time. Also closes the net-scenarios timeout, which predates today by a month. It guessed at a larger timeout or a real hang in the script and it was neither. The stubbed ssh drains stdin, so the tests hung whenever the runner had a live one.
| * chore(tasks): close the clock-deadlock work and file what it turned upCraig Jennings29 hours1-96/+152
| | | | | | | | | | | | Closes the deadlock task and its two follow-ups. The laptop-branch one is cancelled rather than done. Choosing allow-downgrade fleet-wide made all three motivating defaults identical on every machine, so the branch had nothing to put on either side. Three things filed from today. The RTC reset traced to an abrupt power loss at 01:33:18, recorded against the input-cover ribbon task as the cause rather than as a separate bug. The agent-text relay reports success for a page that never arrived, blocked on the shared-asset change being applied. A failed hostname lookup takes seven seconds, measured and set aside.
| * fix(test): pin stdin so the net-scenario harness stops hangingCraig Jennings29 hours1-0/+6
| | | | | | | | | | | | The stubbed ssh is `cat >/dev/null`, which drains stdin to EOF. Without an explicit stdin the stub inherits whatever the test runner had, so it returned instantly when stdin was redirected and blocked forever when it was a terminal or a live pipe. All five tests then hit their 20-second timeout. That made the suite unreliable in the case that matters most, running it by hand. `make test-unit </dev/null` passed while the same target run from a terminal failed, which reads as a flaky test rather than an environment-dependent one.
| * fix(installer): relax DNSSEC to allow-downgrade, keep DoT strictCraig Jennings29 hours1-1/+11
| | | | | | | | | | | | Venue resolvers that mangle DNSSEC records are common on hotel and airport wifi, and DNSSEC=yes turns that into no answer at all rather than an unauthenticated one. The encryption is the half worth being strict about, so DNSOverTLS stays yes. This is not what fixes the clock deadlock, despite being the obvious reach. Resolved downgrades when a server lacks DNSSEC support, and a clock-skew signature failure is a validation failure, so no downgrade fires. Measured on velox: dead across six retries and a reset-server-features. The IP-addressed NTP source is what breaks that.
| * fix(installer): use a stable per-network wifi MACCraig Jennings31 hours1-2/+6
| | | | | | | | A fresh MAC per connection hides the machine from itself as well as from the venue, so every reconnect at a hotel or airport looks like a new device and the portal login starts over. Stable derives a different address per network, so nothing is given up across networks and the reconnect friction goes away. Ethernet already used stable.
| * docs: correct the clock/DNS deadlock mechanism to DNSSECCraig Jennings31 hours3-13/+94
| | | | | | | | | | | | | | | | | | | | I reproduced the failure by winding velox's clock back 27 days with chronyd stopped, and the cause is not what I recorded. Resolved logged signature-expired against the root DNSKEY and every DS beneath it. The DoT handshake to 1.1.1.1:853 verified clean at that same clock, and the Cloudflare certificate runs Dec 2025 to Dec 2026, so it was never outside its window. An RRSIG window is days to weeks while a certificate is good for a year, so a skew that breaks DNSSEC normally leaves DoT untouched. DNSSEC=allow-downgrade does not rescue it either. Resolved downgrades when a server lacks DNSSEC support, and a signature-window failure is a validation failure, so no downgrade fires. Six retries over eighteen seconds plus a reset-server-features, all dead. I briefly believed otherwise off a test whose success was a cache hit. The fix itself is verified end to end. With the clock wound back and no DNS at all, chronyd reached the IP-addressed source and stepped the clock straight back. Also settled: the clock landed on 2026-07-23 because that is systemd 261.2's build date to the minute, and systemd advances a garbage RTC to its own build epoch at boot.
| * fix(check): read NTP sources only from files chrony is told to readCraig Jennings31 hours2-3/+87
| | | | | | | | | | | | | | | | Check 6 globbed /etc/chrony.d unconditionally. A drop-in is inert unless chrony.conf names its directory, and Arch's stock chrony.conf names none, so a machine with the IP-addressed source on disk and no confdir line would show the literal and pass. That is a false pass on exactly the misconfiguration the check exists to catch, and it describes a file chrony never opens. Sources now come only from chrony.conf plus whatever confdir or sourcedir it actually names. The config path is a seam so the confdir logic can be tested against a fixture instead of the real /etc. This should have been in the previous commit, whose message already describes it. I staged before reviewing, fixed the finding, then committed the stale index.
| * fix(installer): give NTP an IP source so a wrong clock can't kill DNSCraig Jennings31 hours5-30/+461
| | | | | | | | | | | | | | | | | | | | | | | | The installer wrote both halves of a deadlock. configure_dns pins DNSOverTLS=yes with DNSSEC=yes, and both validate against the wall clock. The chrony step enables chronyd without writing a config, so the machine runs Arch's stock one, whose only source is a pool hostname. Boot with a wrong clock and DoT validation fails, so nothing resolves. Chrony then can't resolve its pool, so the clock stays wrong. Neither side moves, and recovery takes a second device. Velox hit this on the road and I diagnosed it from a phone. An address needs no DNS and no certificate, so two IP-addressed sources in a drop-in break the cycle whatever caused the skew. Stock chrony.conf reads no drop-in directory, so it gets a confdir line pointing at one. post-rebuild-check grows a sixth check for the same property. It reads sources only from files chrony is told to read. A drop-in beside a chrony.conf that never names its directory is one chrony won't open, so counting it would pass the machine while describing a file nothing reads. The failure taxonomy gains the mode in its DNS layer and a cluster 5 triage line. Its egress-layer clock entry assumed working DNS and offered set-ntp true, which can't recover this. That entry now says so.
| * chore(todo): the installer also leaves the dotfiles clone unable to pushCraig Jennings3 days1-5/+25
| | | | | | | | | | | | Same two lines as the shallow-clone defect, found while pushing today. The dotfiles remote defaults to the public read-only endpoint, so a machine the installer built can fetch but never push. My other machine uses the ssh form, so the rebuilt one was the odd one out purely because the installer made it. That half is a decision rather than a fix, so the task loses its solo tag. The read-only default is right for anyone else installing this, who has no key on the server, and wrong for my own machines. The override already exists, so the only question is where my value lives.
| * chore(todo): file what today's work turned up, and fix two checks that liedCraig Jennings3 days1-36/+241
| | | | | | | | | | | | | | | | Four tasks are new. The installer clones my own archsetup and dotfiles repos with --depth 1, so both came back from the rebuild with seven commits of history instead of hundreds. Power profiles crash on a loop against the daemon this repo now masks. The user manager on that machine is spinning and cannot resolve unit files. The new post-rebuild-check wants its probes routed through one guarded helper, because four separate "the probe failed and the check said ok" bugs is a shape rather than four mistakes. I rechecked two recurring items against their own unblock conditions rather than re-stamping them. The zfs DKMS build is still waiting on an upstream release, and the lyricsgenius integrity workaround still fails for the same structural reason. The credential-history entry has been asking a question git could not answer. The filenames recorded there are not the paths those files live at, and a path git has never seen returns no commits rather than an error, so every check since June came back falsely clean. I corrected them to the real paths, which turn out to be six files rather than five.
| * feat(scripts): add post-rebuild-check for the gaps a reinstall leavesCraig Jennings3 days3-0/+1117
| | | | | | | | | | | | | | | | | | | | A rebuilt machine looks finished and isn't. Five gaps surfaced on velox within two days of its reinstall. Three looked fine on inspection: a stowed unit file, an enabled-looking timer, a present git clone. The script runs those five checks and prints a line for each whether or not it finds anything. Every probe fails closed. A check that cannot run reports a finding rather than a pass, which matters more here than anywhere: a silent no-op in the checker is the exact failure it exists to catch. `systemctl --user` exits 1 with empty output when there is no user bus, so reading that as "no failed units" would call a machine healthy at the moment nothing was checked. Calls are bounded for the same reason. A check that hangs reports nothing at all, and the machine most in need of checking is the one it hangs on. I suppressed three classes of finding, each because the live run produced them and reality disagreed. A timer-activated service is supposed to sit linked and not enabled. One expected tooling file is seed-only, so most projects legitimately never have one. Vendored package trees ship their own example files. Left in, those were 19 of the first run's 27 findings, and a check nobody reads is a check that isn't run. The post-install checklist points at it, and 58 tests cover it.
| * chore(todo): file the obsbot guard poll bug and archive resolved workCraig Jennings5 days2-20/+35
| | | | | | | | | | | | obsbot-wb-guard runs from the shared stow tier, so it starts on machines with no OBSBOT and polls every two seconds forever doing nothing. The task carries the ConditionPathExists fix and the grading, plus the trap that disabling a linked unit by hand deletes its stow symlink. Three resolved subtrees moved to the archive.
| * fix(installer): mask power-profiles-daemon so TLP survives on laptopsCraig Jennings5 days2-3/+113
| | | | | | | | | | | | | | | | | | | | power-profiles-daemon.service declares Conflicts=tuned.service tlp.service auto-cpufreq.service, so systemd TERMs TLP the moment ppd starts. The line is in ppd's unit, not tlp's, so grepping tlp.service for it finds nothing. Leaving ppd disabled was never enough. It ships D-Bus activation files, so the desktop-settings panel's own powerprofilesctl call starts it on demand. Velox ran that way from its rebuild on 2026-08-13 until today. TLP failed at every boot and none of its battery policy applied, while the machine looked correctly configured. I mask and then stop. The mask closes the re-activation window, and the stop is what makes a repair re-run take effect, since a mask alone leaves a running ppd running. I left desktops alone. They have no TLP to conflict with, and the panel's power control needs ppd there.
* | fix(velox): trace the dead touchpad to its own connector, and repair two ↵Craig Jennings9 hours5-165/+460
|/ | | | | | | | | | | | | | | | | | | | | | | | | | | lost todo headings The touchpad fault was an interrupt line that never fired: the device enumerated, hid-multitouch bound, and the handler sat correctly on amd_gpio pin 8, but the count stayed at zero across all 24 CPUs under active use and the i2c-HID reset timed out at every boot. A live USB reproduced it exactly, which ruled out software. The fix was the touchpad's own connector — the input-cover ribbon I reseated first fixed the phantom power button and left this untouched, and the 4-pin connector beside the silkscreen is GND and VCC only, so it could never have carried i2c. Both faults from the mainboard swap are now closed. Two task headings had been overwritten by inserts at the top of Open Work, and I recovered both verbatim from the commits that introduced them. One displaced task had ridden an archived parent into Resolved, so an open bug had been sitting outside Open Work for weeks. Filed the install placeholder passwords still live on this laptop as an [#A], graded on severity alone rather than the frequency matrix: full-disk encryption protected by a dictionary word does no work at all on a machine that travels. Corrected the ARCHSETUP_DIR line in the reinstall runbook. It carried a tilde on the right-hand side of an assignment, which zsh does not expand, so following it would have produced an ISO with the installer silently absent.
* chore: rebuild velox and file what the reinstall exposedCraig Jennings6 days3-272/+416
| | | | | | The mainboard swap left no boot entry, so I reinstalled from the archangel ISO rather than repairing a ZFS-root machine a stock USB can't read. Ran it as a disaster-recovery drill: microcode, keys, repos, and data are back, and hibernate now works end to end on a 100G encrypted swap. The tasks are most of what this bought. Reseating the input-cover ribbon is [#A] for today, because four phantom power-button presses and the dead touchpad are one loose connector, and the last one cut power below systemd. The rescued emacs-wttrin bundle rides along until it lands on its remote; the runbook stays until velox is settled.
* feat(installer): set a 90-minute suspend-to-hibernate ceilingCraig Jennings7 days3-1/+176
| | | | | | | | systemctl suspend-then-hibernate reads HibernateDelaySec, and unset it depends on the hardware: a machine with a battery hibernates on a low-battery alarm at an hour nobody chose, and one without falls back to systemd's 2h default. 90 minutes states a ceiling both machines share. A laptop can still hibernate earlier, because systemd runs both timers and takes whichever fires first. The number is a tradeoff and the drop-in carries it: long enough that stepping out of a meeting costs a screen unlock rather than a passphrase and a full resume, short enough that a laptop left in a bag drops its encryption keys out of RAM. A suspended machine is still holding them. Numbered 60- because systemd reserves 10-40 for vendor drop-ins under /usr and 60-90 for local ones under /etc. A 10- file here would sort below a vendor drop-in and quietly lose to it.
* chore(todo): velox reinstall runbook and the tasks it surfacedCraig Jennings7 days2-1/+274
| | | | | | The runbook drove today's rebuild: preflight, a required salvage pass, the install, and post-install verification. It stays as the working record until velox is settled. Filed from the rebuild: reseating the input-cover ribbon, which is [#A] for tomorrow because phantom power-button presses have killed the machine four times and the last one cut power below systemd, where no setting can catch it. The rest are hibernate in the settings dial, a truenas VM for long-running sessions, the keyboard-backlight binding, and the screen-lock suite that fails 21 of 23 on ratio.
* feat(installer): grant brightness control to the video groupCraig Jennings7 days4-0/+211
| | | | | | | | Arch's brightnessctl ships no udev rules and leans on logind, which grants brightness writes only to the active seat session. Anything outside that session (a script, an ssh shell, a panel launched into a different one) meets root-owned sysfs and gets EPERM. On velox both panel sliders were dead after a fresh install. configure_backlight_access writes a udev rule making the backlight and keyboard-LED brightness attributes group-writable by video, which create_user already adds the user to. I granted the keyboard LED to video rather than input: anyone in input can read every input device, which is too much authority for dimming a keyboard. essential_services is already marked complete on machines installed before this step, so a re-run skips them. The post-install checklist carries the manual route.
* chore(todo): file the secrets-repo hardening and its follow-upsCraig Jennings10 days1-4/+50
| | | | I filed the task to move secrets out of the shareable dotfiles repo into a private store delivered via a personal ISO, with the rotation and reconcile work it depends on. The design detail and the incident record stay in a local unpublished doc, not this public repo. I also stamped the two settled network-panel decisions: metered detection and saved-connection ordering.
* feat: enable the podman API socket and ship the camera udev grantCraig Jennings11 days5-36/+259
| | | | | | | | | Two one-time machine setups from the winvm handoffs now happen at install time. - The devops podman block enables the rootless podman API socket. Socket-activated, so it costs nothing idle, and API clients like Pods fail with an empty window without it. enable_user_service grew an optional wants-target argument because a socket unit's [Install] is WantedBy=sockets.target. The old default.target link would never socket-activate. - install_camera_passthrough_rules ships 72-usb-passthrough-cameras.rules: GROUP="video", MODE="0660" plus the uaccess tag on the OBSBOT and BRIO USB IDs, so usbredirect can claim them for VM passthrough. The filename is load-bearing: logind's ACL is applied by 73-seat-late.rules, so the tag only works from a file sorting below 73. A test pins that property. Both are live on ratio (the old 99- rules file is retired there). Whether uaccess alone would suffice from the corrected position is untested and stays documented as a hypothesis.
* chore(todo): file the pre-vacation morning-review listCraig Jennings11 days1-0/+44
| | | | I swept every open task against the 2026-08-15 departure and filed the ranked list as a scheduled VERIFY for the morning. The net-scenarios timeout flake also got a dated recurrence note: it fired again under concurrent suite load and cleared standalone.
* chore(todo): two review cycles, vacation re-grades, post-setup closureCraig Jennings11 days1-43/+148
| | | | | | | | | | I reviewed fourteen tasks across two cycles and re-graded around the coming vacation. Closed: the Comet KVM setup (I wired it up by hand and both truenas and the KVM are back on the tailnet), the waybar separators (fixed a while back), and the 2026-05-11 VM-error container (the residual four are environmental). Killed: whole-display dim (the July auto-dim work covers the need) and the annual tool-pain-points review (an undated intention that never fired). Vacation re-grades: osbot camera and the velox post-setup review raised and scheduled, laptop sleep/suspend raised to A for Monday. Carousel layout demoted to C. Filed the podman-socket and camera-udev task from the winvm handoff.
* docs: add the post-install checklist and podman/camera-udev notesCraig Jennings11 days2-0/+118
| | | | The checklist is the standing home for manual post-first-boot steps: bluetooth pairing and the Proton Bridge login start it. The podman-socket and camera-udev notes carry the evidence for the filed install-time task, including why uaccess alone can't grant a raw USB node.
* feat: automate microcode, TLP radio enable, and ZFS tmp.mount maskCraig Jennings11 days5-9/+380
| | | | | | | | | | The 2026-04 velox setup left three manual fixes behind. All three now happen at install time. - The TLP config sets DEVICES_TO_ENABLE_ON_STARTUP="bluetooth wifi". systemd-rfkill is masked on laptops because it fights TLP, so TLP is the only thing left that can restore radio state. Without this a fresh install can boot with both radios soft-blocked. - mask_tmp_mount_for_zfs masks systemd's tmp.mount when the pool carries a dataset mounted at /tmp, so tmpfs can't shadow the dataset and break systemd-tmpfiles. - install_cpu_microcode installs intel-ucode or amd-ucode by vendor_id, first in boot_ux so grub-mkconfig and mkinitcpio's microcode hook both see the ucode image. New tests cover each function across normal, boundary, and error cases. The boot_ux and snapshot-dispatch sequence pins include the new calls.
* chore(todo): close a fixed lock-chain bug, re-scope the world face, file twoCraig Jennings2026-08-041-44/+99
| | | | | | | | | | | | | | | | | | | The idle-commit lock-chain bug was fixed on 2026-07-29 and stayed open at [#A] six days past deadline. Verified against the tree rather than the commit message: the wrapper is in the rendered chain, the live config matches, and the test that used to pin the bug now pins the fix. The evidence the task itself named is that the relaunch log is receiving entries, so the instrument is present rather than silently removed. Recorded a finding that changes the night-watch task's premise. Two relaunches on 2026-07-30 postdate the mitigation, and the watchdog logs the exit code but not the sender, so "the night watch is the only thing killing hyprlock" is now unproven. Instrument before designing the handshake. The world face lost half its premise when the 07-31 rebuild dropped the layout flag, so it re-scopes to the hour-format toggle alone and drops to [#C]. Filed the decaying spine tests and answered the drift audit's open delivery question, which is what let it take :solo:.
* docs: keep the timeline face's design history, not its engineCraig Jennings2026-07-3110-0/+1509
| | | | | | | | Six prototypes from the world-face work, kept as the record of how the design got to where it is. The first five are self-contained; prototype 6 and the option-A pages load the engine, so they read here but do not run here. The engine stays out on purpose. It carries the list of places I travel to, with coordinates, and this repo is published — a design record is not worth publishing that for. The README says how to copy the modules in locally to run prototype 6, and gitignore keeps such a copy from being committed by accident. Dropping the prototype test target with it: the engine and its tests now live in one place, so the suite runs once rather than twice over identical files.
* chore(todo): archive resolved work and move the wolf config out of the treeCraig Jennings2026-07-291-67/+64
| | | | | | Three finished subtrees move into Resolved: the runpm reboot, the caffeine readability fixes, and the relaunch-logging task that its own instrument superseded. The encrypted wolf config now lives outside this repo. Leaving it untracked in the working tree was the wrong resting place, because one "git add -A" would put a live key into a repo that cgit still serves anonymously. The importer cannot read an encrypted config anyway, so keeping it here bought nothing.
* docs(todo): record the lock-chain regression and the watch collisionCraig Jennings2026-07-291-2/+105
| | | | | | | | | | The night watch and the screen-lock watchdog fight over the session lock. The watch kills hyprlock by design to reveal its kiosk, and the watchdog reads that SIGTERM as a crash and relaunches. That is the root cause of the lockdead screens, and it retires both earlier theories: the AMD parameter was live throughout, and nothing ever crashed. Also files the renderer regression that dropped the wrapper out of lock_cmd, and the "SCREEN OFF" label that reads as a status report rather than the action its stage performs. Three gradings corrected after review. Two claimed a security carve-out for what is really an availability problem, which inflated them past what the matrix gives. A third reached [#C] and wrote [#B] beside it, which overrides the letter instead of fixing the input. Each correction is recorded in its own task body rather than quietly applied, so the reasoning can be argued with. The reboot task's claim that amdgpu.runpm=0 was the root cause is marked superseded for the same reason.
* docs(todo): close the reboot and caffeine fixes, file four findingsCraig Jennings2026-07-281-0/+160
| | | | | | | | | | The 2026-07-28 reboot cut the session short before two finished tasks could be closed. amdgpu.runpm=0 is confirmed live in /proc/cmdline, and the caffeine readability work shipped, so both close now. Four new entries. Desktop settings didn't survive a session restart. Timer presets should start in one click. hyprlock still exits mid-lock, and its watchdog relaunch left no durable trace. The wireguard gpg convention is inert: the importer globs *.conf only and carries no gpg call, so the stated promise that it decrypts at import is false. That last one is why the newly encrypted wolf config stays untracked for now. The hyprlock grading first read "some users sometimes", which the matrix maps to P3 rather than the [#B] written beside it. The frequency row was the wrong input. On a one-user machine, twice in three days is frequent, so I corrected the input rather than the letter. Also corrected an earlier claim that night light "has likely never worked" from the config. It launches fine by hand and survives. It loses a race against compositor readiness at session start, and nothing relaunches it.
* docs: archive resolved publish-lock decisionCraig Jennings2026-07-271-8/+7
| | | | I moved the completed coordination decision into the resolved work log.
* docs: record repository-scoped publish-lock decisionCraig Jennings2026-07-271-17/+5
| | | | I chose one repository-scoped lock for sessions sharing a clone. It protects reconcile through commit without blocking ordinary edits.
* docs(todo): archive refactor and desktop feature batchCraig Jennings2026-07-251-35/+58
|
* refactor(prototypes): merge casting widgets into Dupre kitCraig Jennings2026-07-259-67/+284
|
* refactor(test): share runner and scenario contractsCraig Jennings2026-07-258-224/+329
|
* docs(specs): record shipped settings and network follow-upsCraig Jennings2026-07-252-0/+2
|
* docs(todo): file 2 roam items, archive completed tasks (wrap-up)Craig Jennings2026-07-251-801/+789
| | | | File the two archsetup-owned roam captures (auto-dim forgotten on layout change; maint queue copy button), and archive 2 completed level-2 tasks to Resolved via the wrap-up cleanup.
* docs(todo): update floating-layout manual test for the setfloating rebuildCraig Jennings2026-07-251-9/+9
| | | | Floating is now Super+Shift+F (per-window setfloating), the glyph flips, and the click is master<->monocle. Rewrote the checklist steps and the state-file path to match.
* docs(todo): log verified worldclock bad-timezone-row bugCraig Jennings2026-07-251-0/+8
| | | | Sentry found that waybar-worldclock crashes its whole tooltip render on a single malformed timezone row in worldclock.conf. Graded P4 [#D] (minor x rare), with repro and fix sketch.
* docs(todo): file wallpaper-panel task and floating-mode manual testCraig Jennings2026-07-251-0/+22
| | | | File the roam-inbox wallpaper-panel item (open at the current wallpaper, select it in the pane, keep scroll position) as a solo feature task, and add the floating-mode live check to the manual testing checklist.
* docs(todo): record the hyprlock AMD-iGPU DPMS lockout and its fixCraig Jennings2026-07-241-0/+25
|
* fix(installer): harden the lock path against the AMD-iGPU DPMS lockoutCraig Jennings2026-07-244-0/+166
| | | | | | | | | | | | An idle lock on this Strix Halo box wedged the whole session: hyprlock died and the compositor stayed locked with no prompt, recoverable only from a console. It's a documented AMD-integrated-Radeon failure (hyprlock#953, Hyprland#5822) -- a display power cycle via DPMS invalidates the GPU resources the lock client holds, so hyprlock loses its surface and exits without unlocking. No coredump, no OOM; the GPU pulls the rug out. Two installer changes, both scoped and tested: update_grub_cmdline adds amdgpu.runpm=0 on AMD machines only. Disabling GPU runtime power management keeps those resources valid across a display cycle -- the root fix. A no-op on Intel/NVIDIA, and it rides the existing merge so no boot-critical token is touched. configure_hyprlock_pam writes a complete PAM stack. The hyprlock package ships only `auth include login`, leaving account and session uninitialised so pam_end() crashes on cleanup -- a separate documented lockout cause. All three phases now resolve through login, inheriting the keyring the graphical login uses. CALL_SITES pins both new wirings. 372 unit tests, exit 0; each addition proven by reverting it.
* docs(todo): close seven speedrun tasks and record the two research assessmentsCraig Jennings2026-07-241-9/+41
| | | | Timer hero hierarchy + RING removal, video fit, PTT glow, world-face bold, calc-toggle, and the floating-clock keychord all shipped in dotfiles. The floating-layout and window-config research each produced an assessment doc with a build recommendation.
* docs(todo): file five roam inbox-zero items routed from workCraig Jennings2026-07-241-0/+36
| | | | Two hyprland research ideas (floating-as-easiest-mode, save/recall window layouts), a floating-clock keychord that resolves the round-6 do_activate question, a calc-scratchpad toggle bug, and a world-face city-name weight tweak.