Problem
A persistent mount-root invariant violation causes Relayfile to write a new INCIDENT-<timestamp>.md on every poll cycle. When the invalid mount root is not a directory (for example, a symlink), the report falls back to the mount root’s parent — commonly the consumer repository root.
The invariant correctly fails closed, but the reporting path is unbounded and poll-frequency-driven. One unresolved operator condition becomes an endless stream of new files in another project’s working tree.
Live evidence
In AgentWorkforce/burn, .integrations is a symlink. A running Relayfile mount checked it on roughly five-minute intervals and wrote 11 untracked files into the repository root:
INCIDENT-20260729T181749Z.md through INCIDENT-20260729T190816Z.md
The reports are identical except for timestamp. The observed times are 18:17:49, 18:23:04, 18:28:03, 18:32:59, 18:37:52, 18:42:43, 18:48:05, 18:53:21, 18:58:20, 19:03:14, and 19:08:16 UTC.
This is independent of whether the symlink itself is a supported layout. A daemon should not create an unbounded number of recovery artifacts for one unchanged fault, especially in a consumer repository where they can be committed accidentally.
Root cause
internal/mountsync/invariants.go:
Syncer.assertMountRootInvariant() calls WriteIncidentReport() whenever CheckMountRootInvariant() fails.
Syncer.sync() invokes that assertion at the top of every sync cycle.
WriteIncidentReport() always chooses a timestamped filename.
- When
localRoot is not a directory, its candidate destination begins with filepath.Dir(localRoot), which is the repository root for a .integrations mount.
There is no deduplication, rate limit, “already reported” state, or stable incident identity.
Expected behavior
- Preserve the first durable report for a distinct invariant violation.
- Repeated checks of the same unchanged
(localRoot, kind, reason) should update/reuse one report, rate-limit reminders, or log against the existing report rather than create new files.
- A fallback report should not pollute the consumer repository root by default. Prefer a Relayfile-owned state/log directory or the system temp directory when
.relay/ under the mount root is unavailable.
- A materially changed violation should still produce a new report.
Regression coverage
Run multiple sync cycles against the same symlink/non-directory root and assert:
- the invariant remains failed closed;
- only one durable incident artifact is created for the unchanged condition;
- no
INCIDENT-*.md files appear in the consumer project root.
Problem
A persistent mount-root invariant violation causes Relayfile to write a new
INCIDENT-<timestamp>.mdon every poll cycle. When the invalid mount root is not a directory (for example, a symlink), the report falls back to the mount root’s parent — commonly the consumer repository root.The invariant correctly fails closed, but the reporting path is unbounded and poll-frequency-driven. One unresolved operator condition becomes an endless stream of new files in another project’s working tree.
Live evidence
In
AgentWorkforce/burn,.integrationsis a symlink. A running Relayfile mount checked it on roughly five-minute intervals and wrote 11 untracked files into the repository root:INCIDENT-20260729T181749Z.mdthroughINCIDENT-20260729T190816Z.mdThe reports are identical except for timestamp. The observed times are 18:17:49, 18:23:04, 18:28:03, 18:32:59, 18:37:52, 18:42:43, 18:48:05, 18:53:21, 18:58:20, 19:03:14, and 19:08:16 UTC.
This is independent of whether the symlink itself is a supported layout. A daemon should not create an unbounded number of recovery artifacts for one unchanged fault, especially in a consumer repository where they can be committed accidentally.
Root cause
internal/mountsync/invariants.go:Syncer.assertMountRootInvariant()callsWriteIncidentReport()wheneverCheckMountRootInvariant()fails.Syncer.sync()invokes that assertion at the top of every sync cycle.WriteIncidentReport()always chooses a timestamped filename.localRootis not a directory, its candidate destination begins withfilepath.Dir(localRoot), which is the repository root for a.integrationsmount.There is no deduplication, rate limit, “already reported” state, or stable incident identity.
Expected behavior
(localRoot, kind, reason)should update/reuse one report, rate-limit reminders, or log against the existing report rather than create new files..relay/under the mount root is unavailable.Regression coverage
Run multiple sync cycles against the same symlink/non-directory root and assert:
INCIDENT-*.mdfiles appear in the consumer project root.