Honor external edits to heartbeat-tasks.json / 心跳任务文件的外部编辑不再丢失#6131
Merged
SivanCola merged 1 commit intoJul 6, 2026
Merged
Conversation
heartbeat-tasks.json is documented as human- and AI-editable (file header + the heartbeat panel tip), but the engine loaded it once at startup and then treated its in-memory copy as the source of truth: - an externally added task was never scheduled until a manual Refresh or an app restart, and - any run-state save (mergeRunUpdatesLocked writes the full list after a task fires) silently rolled the external edit back — the same "my write did not take" shape the session-data guard exists for, except here the product explicitly invites the edit. Two changes make the contract real: - mergeRunUpdatesLocked now rebases onto the on-disk list before its full-list save: the engine owns only the run-state fields (TopicID, LastRunAt, CreatedAt backfill), so external additions, edits, and deletions survive the save. A missing/unreadable file falls back to the in-memory list, preserving the historical behavior (and the existing concurrent-edit test). - tick() probes the config mtime and adopts external edits before scheduling, so an agent-added task runs on the next tick. The engine records the mtime after its own writes to avoid re-reading them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
heartbeat-tasks.jsonis documented as human- and AI-editable (the file header indesktop/heartbeat.goand the heartbeat panel tip: "AI agents can also edit heartbeat-tasks.json"), but the engine only half-honored that contract:mergeRunUpdatesLockedpersists the full list after a task fires) was based on that stale in-memory copy, so it silently rolled back external additions/edits/deletions — the same "my write didn't take" shape the session-data guard (Fix recovery-copy UX and guard agent writes to session data / 修复冲突副本体验并防护 agent 直写会话数据 #6123) exists to prevent, except here the product explicitly invites the edit.Changes
mergeRunUpdatesLockedrebases onto the on-disk list before its full-list save. The engine owns only the run-state fields (TopicID,LastRunAt,CreatedAtbackfill); task definitions added, edited, or deleted externally are adopted from disk, so the save can no longer roll an external edit back. A missing/unreadable file falls back to the in-memory list (historical behavior, and what the existing concurrent-edit test pins).tick()probes the config file's mtime and adopts external edits before scheduling, so an agent-added task runs on the next 30s tick instead of waiting for Refresh/restart. The engine records the mtime after its own writes (Start/ReloadTasks/ReplaceTasks/merge) so it does not re-read files it just wrote.ReplaceTasks(the UI panel save) keeps its whole-list semantics: saving what the panel shows is the user's explicit intent.New regressions: external edit + addition survive a run-state save (in memory and on disk), and a tick adopts an externally added task (mtime forced forward so coarse filesystem timestamps cannot flake).
Validation
cd desktop && go test .(heartbeat suite incl. the 2 new regressions) and fullgo test ./...— greengo vet ./gofmt— cleanTestHeartbeatMergeRunUpdatesPreservesConcurrentEditsAndDeletesstill passes unchanged (missing-file fallback preserves its semantics)Follow-up to the review discussion on #6123 (the guard correctly stopped hard-blocking this file; this PR makes the advertised editability actually work).