fix(watcher): refusals end in a terminal state; pin every converted writer (#158)
CI / Lint / Test / Vet (pull_request) Successful in 1m6s
CI / Mirror to GitHub (pull_request) Skipped

Review round 1 on PR #195:
- A refused marker or archive write left no marker, so the note was
  reprocessed every interval (archive copies piling up; an LLM call per
  round on the failure path). The marker check now uses Lstat (any entry
  at the marker path counts, so a dangling marker link skips the note
  instead of looping), and a note whose archive copy or marker write is
  refused is remembered (path, size, mtime) and not retried until it
  changes.
- cleanRel no longer refuses a backslash: it is a legal filename byte on
  Linux, not a traversal, and a raw note named with one was never
  archived or marked.
- Tests now reach every converted writer: the log.md append (real
  raw/failed so the log is reached, symlinked log.md), a dangling marker
  link, the refused-retry loop with a positive control, a backslash name,
  a buildAndWrite swap race, and the claude-session archive with in-brain
  and outside symlinked archive dirs. The stale lint allowlist entry for
  appendWatcherLog is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 23:40:19 +02:00
co-authored by Claude Opus 5.5
parent 77c44f298c
commit 1a2a93d2f4
6 changed files with 169 additions and 9 deletions
+1 -1
View File
@@ -109,7 +109,7 @@ func (b *Brain) ReadDirRegular(relDir string) ([]string, error) {
// after following a symlink, and a ".." after a symlinked directory would
// otherwise pass the check and redirect the read or write.
func cleanRel(rel string) error {
if rel == "" || path.Clean(rel) != rel || !filepath.IsLocal(rel) || strings.Contains(rel, "\\") {
if rel == "" || path.Clean(rel) != rel || !filepath.IsLocal(rel) {
return fmt.Errorf("%q: not a clean brain-relative path: %w", rel, ErrNotRegular)
}
return nil