Lot 9(a): reload the configuration as it changes, and show a fault in the icon - #9
Merged
Merged
Conversation
The watcher used to read config.toml once, and a file it could not use made it exit with a code and no icon. Now `serve` loads the file itself and a supervisor on the worker thread runs one engine per usable configuration: a thread parked on the folder's change notification (`config::watch`, 250 ms settle, bytes compared) signals a reload, the engine stops through the handover path with the session left open in the marker, and the next engine resumes it -- a game in progress is not disturbed, and no new engine state was needed. A file that cannot be used freezes the program instead: `LoadError` carries a one-line summary (`line 3: unknown field ...`, `the file is missing`, the validation's sentence), a `FaultSink` beside the session sink hands it to the tray, and the tray draws the reserved error state with the summary as the menu's first line. `log_level` follows live through a reload layer; `log_dir` waits for the next start and says so. `StopSignal` gains a `Reload` reason and a child signal: the engine runs on a child of the process-wide stop, whose own event carries the reload and is reset between engines while the parent is never reset, so a Quit during a reload cannot be lost. Exit codes 3 and 4 are now the other commands'. Six new tests: the summaries, the watch on a real folder, the reload scenario in the engine, the fault on every tray surface. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Getting started no longer tells people to stop and restart the watcher after an edit; the recipes say the same, with install-task kept for the zip's first install. The icon table and the troubleshooting section gain the red, slashed icon; How it works explains the reload, the handover it rides on and why an unusable file freezes the program rather than falling back; the reference notes what applies live and that the exit codes are the commands'. The changelog's Unreleased section carries the three lines for the person running it. Lot 9's page records the mechanics as built -- the engine restarted through the handover, not the RwLock the plan named, and why -- and the measurement of 2026-09-19; Lot 6's reserved state has its meaning. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two things the field run of 2026-09-20 found. `log_level = "debg"` passed validation, gave the filter no directive it knew, and the log fell back to errors alone -- quiet for ninety seconds, the reload line that would have explained it filtered out with the rest. The five levels are now validated, case-insensitively, and a sixth word is a fault with the icon and the menu line. And the debug line at the writer's exit, after a resume, read "the game was never named" with a 34 s session: the resumed signal has a name and no process id, and the engine's clock starts at the resume. It now says the game was known by name only, from the resumed session, with the time since the resume. Lot 9's page records the run -- a reload and a fault, each during a Starfield session -- and closes the item. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
On the maintainer's remark after the field run: the red icon is easy to miss at logon and the menu line was too long to read. A fault is now said with a silent notification carrying the shell's error glyph and the whole summary, at start and at every reload that fails, and the end of a fault is said too, so the person knows the watcher is watching again; a reload that stays usable says nothing. The menu keeps a headline, the summary cut before the parser's list of expected fields. The supervisor reports which transition each read is -- faulty, restored, usable -- because the notice depends on what came before; the tray owns the wording. The Discreet principle in AGENTS.md now names the two things the program says unasked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The maintainer broke the file, stopped the watcher, fixed the file and started it again: no word, since the new process had never seen the fault. A fault is now noted in a second file beside the session marker, `configuration-fault`, removed when a usable file is read; a start that removes one says the fault is over, and a start on a file that was usable all along stays silent as before. `status` reports the file and `purge` removes it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The watcher reads
config.tomlagain whenever it changes, and a file it cannot use no longer makes it exit: the icon turns red, a notification says why, and nothing runs until it is fixed. Lot 9's configuration item, built 2026-09-19 and verified in the field on 2026-09-20.What changed for the person running it
Configuration reloadedin the log. A game in progress is not disturbed: the engine hands the session to its successor the way an update does, and the commands that run when the game ends are the ones just saved.log_levelfollows live;log_dirwaits for the next start and says so.line 3: unknown field 'log_levl', expected one of …); a menu line with the short of it; anERRORline in the log. Nothing runs until it is fixed, not even the stop half — frozen, deliberately, never a fallback to the last good file. Saving a good one brings the icon back and a notification says the watcher is watching again, also after a restart on a file fixed while it was stopped.log_level = "debg"used to be accepted and to leave a log with nothing but errors in it, silently. Now a fault like any other.How it is built
RwLock. The plan named anArc<RwLock<Config>>read at each use; that would have covered a valid change and left the invalid case — frozen idle, frozen mid-game, a recovery afterwards — to new engine states. Lot 13's handover already was those three, so a change to the file is a handover from one engine to the next in the same process, and the engine changed by one match arm.docs/design/09-robustness.mdrecords the plan and what was built, and why.StopSignalgains aReloadreason and a child signal: the engine runs on a child of the process-wide stop; the child's own event carries the reload and is reset between engines, the parent is never reset, so a Quit during a reload cannot be lost.config::watch:FindFirstChangeNotificationWon the folder, a 250 ms settle after the last notification, bytes compared before signalling.LoadErrorwithsummary()andheadline()replaces the two marker structs; exit codes 3 and 4 are now the other commands'.Report::Faulty | Restored | Usable) so the tray can word the two notices without knowing the history. Aconfiguration-faultfile beside the session marker carries a fault across processes;statusreports it,purgeremoves it.Measured
For the reviewer
AGENTS.md's Discreet principle now names the two things the program says unasked; the tray convention names the supervisor's verdict.install-taskfor the zip's first install.🤖 Generated with Claude Code