HarperFast / HarperFast/harper
OptionsWatcher can lose a config write that lands milliseconds after the previous one
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Summary
Two `set_component_file` writes to a component's `config.yaml` arriving in quick succession (observed: 9ms apart) can result in the second write never being observed by the component's `OptionsWatcher` — the live config keeps the first write's values until some later event touches the file.
## Evidence
Observed while developing an integration test for the static plugin (branch `kris/static-cache-headers`): an alternating pass/fail pattern where every config update issued immediately after a fast-succeeding previous update was lost. Harper log excerpt showing the paired writes:
```
2026-07-09T23:48:09.802Z [main/0] [info] [operation]: { operation: 'set_component_file', project: 'static-cache-headers', file: 'config.yaml' }
2026-07-09T23:48:09.811Z [main/0] [info] [operation]: { operation: 'set_component_file', project: 'static-cache-headers', file: 'config.yaml' }
```
The first write was applied (served headers changed); the second never was, across a 15s polling window.
## Analysis
`components/OptionsWatcher.ts#handleChange` itself is sound — every chokidar event triggers a fresh `readFile`, so last-write-wins on contents. The loss is at the chokidar/inotify layer: a write landing while the watch is being re-established (e.g. after an atomic replace/rename from the prior write) emits no event, and nothing self-heals afterward because no later event arrives.
## Impact
Low-frequency but user-visible: two quick config saves (studio, deploy tooling, scripts) can leave the component running the older config with no error. Same seam presumably affects any watched config, not just `static`.
## Suggested direction
- Debounced re-read after the last observed event (cheap self-heal), or a slow periodic mtime check as a safety net, in `OptionsWatcher`.
- Alternatively have `set_component_file` nudge the watcher (it knows the write happened).
— found while testing HarperFast/harper#1746's static-plugin follow-up; reported by Claude (Opus 4.8) with Kris
Contributor guide
Research direction
Start at components/OptionsWatcher.ts#handleChange and inspect how its chokidar watch is re-established after config.yaml writes or atomic replacements. Reproduce two set_component_file writes about 9ms apart, then verify that the component observes the second write without needing a later filesystem event.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100