HarperFast / HarperFast/harper

OptionsWatcher can lose a config write that lands milliseconds after the previous one

Open
#1,747 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.