Stop writing an empty refusal-counter file on every stop of every session (issue 1749)
mesh/merge-gate head e3a714d5f0f0 merged into trunk c3564c1accf3 — pass: builds claude-code → ace, g14, novox, shanks; no bus step; every machine composes …
mesh/repo-check head e3a714d5f0f0 merged into trunk c3564c1accf3 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered

writeRefusalCounters wrote "{}" and, since it now routes through fsys
(this branch's earlier commit), created the waits folder on every single
stop, even for a session that never had a wait: one counter file per
session id, piling up on a node that uses the wait list at all. It now
removes the file instead of writing empty counters, a no-op when there
was never one to begin with, so a stop with nothing to record leaves
neither the file nor the folder; a refusal still writes it, and the
stop right after the wait is done (or let through) removes it again.
This commit is contained in:
jochen
2026-10-21 19:41:05 +02:00
parent 08cec8cb1c
commit e3a714d5f0
2 changed files with 82 additions and 11 deletions
+20 -8
View File
@@ -113,14 +113,26 @@ func readRefusalCounters(waitsDir, session string) map[string]int {
return m
}
// writeRefusalCounters writes the counter file beside the waits file, through fsys like every other write
// into the agent's home (novox/hq ADR 0266, issue 1749): called from the Stop hook, which already runs as
// the agent's own account (fsys is then its zero value, a plain write, as before), and from the tool's
// AdoptName, which runs as the operator's account and must reach a confined node's agent home through the
// sudo helper fsys carries such a write through. Its caller decides what an error here means: harmless when
// the stop is already allowed, but when the stop was about to be refused, a cap that cannot be written is a
// cap that cannot take effect (ADR 0489 §5 "never loops", review round 1 item 2).
// writeRefusalCounters keeps the counter file beside the waits file in step with m, through fsys like every
// other write into the agent's home (novox/hq ADR 0266, issue 1749): called from the Stop hook, which
// already runs as the agent's own account (fsys is then its zero value, a plain write or remove, as
// before), and from the tool's AdoptName, which runs as the operator's account and must reach a confined
// node's agent home through the sudo helper fsys carries such a write through. Its caller decides what an
// error here means: harmless when the stop is already allowed, but when the stop was about to be refused, a
// cap that cannot be written is a cap that cannot take effect (ADR 0489 §5 "never loops", review round 1
// item 2).
//
// Empty, m is removed rather than written as "{}" (issue 1749, follow-up): a stop with nothing to record —
// every stop of every session with no waits, the ordinary case — must leave neither the file nor, the first
// time, the waits folder itself; removing a file that was never there is not an error.
func writeRefusalCounters(waitsDir, session string, m map[string]int) error {
path := refusalCountersPath(waitsDir, session)
if len(m) == 0 {
if err := fsys.Remove(path); err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
}
return nil
}
raw, err := json.Marshal(m)
if err != nil {
return err
@@ -128,7 +140,7 @@ func writeRefusalCounters(waitsDir, session string, m map[string]int) error {
if err := fsys.MkdirAll(waitsDir, 0o700); err != nil {
return err
}
return fsys.WriteFile(refusalCountersPath(waitsDir, session), raw, 0o600)
return fsys.WriteFile(path, raw, 0o600)
}
// notice says a fail-open or let-through reason on both the log (stderr) and the screen: Claude Code shows a