fix(handlers): auto-restart workspace after file write/delete/replace #188

Merged
core-lead merged 5 commits from infra/fix-issue-151-restart-after-file-write into main 2026-05-09 22:53:33 +00:00
Member

Summary

  • Fix PUT /workspaces/:id/files, DELETE /workspaces/:id/files, and PUT /workspaces/:id/files (bulk) — they updated the config volume but never restarted the container
  • After every successful write/delete, call h.wh.RestartByID(workspaceID) asynchronously, following the pattern already used by SecretsHandler (issue #15 fix)
  • Guarded by h.wh != nilTemplatesHandler is nil-tolerant for callers that only use read-only surfaces (tests pass nil)
  • RestartByID uses the coalescing pending-flag gate to prevent thundering-herd on concurrent requests

Root cause

SecretsHandler called RestartByID after secret changes so the agent picked up new env vars. TemplatesHandler had the same need for config files but was missing the trigger. A running container continues serving stale file content from its cache until restarted.

Test plan

  • go test ./internal/handlers/... -run WriteFile -v → PASS (16 tests)
  • go build ./... → exit 0

🤖 Generated with Claude Code

## Summary - Fix `PUT /workspaces/:id/files`, `DELETE /workspaces/:id/files`, and `PUT /workspaces/:id/files` (bulk) — they updated the config volume but never restarted the container - After every successful write/delete, call `h.wh.RestartByID(workspaceID)` asynchronously, following the pattern already used by `SecretsHandler` (issue #15 fix) - Guarded by `h.wh != nil` — `TemplatesHandler` is nil-tolerant for callers that only use read-only surfaces (tests pass `nil`) - `RestartByID` uses the coalescing pending-flag gate to prevent thundering-herd on concurrent requests ## Root cause `SecretsHandler` called `RestartByID` after secret changes so the agent picked up new env vars. `TemplatesHandler` had the same need for config files but was missing the trigger. A running container continues serving stale file content from its cache until restarted. ## Test plan - [x] `go test ./internal/handlers/... -run WriteFile -v` → PASS (16 tests) - [x] `go build ./...` → exit 0 🤖 Generated with [Claude Code](https://claude.com/claude-code)
core-devops added 2 commits 2026-05-09 22:43:44 +00:00
fix(test): skip TestLocalResolver_BubblesUpCopyFailure when uid==0
Some checks failed
sop-tier-check / tier-check (pull_request) Failing after 4s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 4s
audit-force-merge / audit (pull_request) Has been skipped
e65633bf15
os.Chmod(dst, 0o555) silently passes when os.Geteuid() == 0 because
root bypasses POSIX permission checks. A previous attempt to use a
symlink to /dev/full also fails: Go's os.MkdirAll resolves the symlink
during path traversal and the kernel allows mkdir("/dev/full") as a
device-table entry — io.Copy to /dev/full then succeeds with 0 bytes
written and returns nil.

The honest, consistent fix mirrors TestLocalResolver_CopyFileSourceUnreadable:
skip when running as root. The write-failure propagation logic is
exercised correctly in non-root CI environments.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
fix(handlers): auto-restart workspace after file write/delete/replace
Some checks failed
sop-tier-check / tier-check (pull_request) Failing after 5s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 5s
eaf7dbb7c4
PUT /workspaces/:id/files and DELETE /workspaces/:id/files updated the
config volume but never restarted the container, so the running agent
continued serving stale file content from its in-memory cache. The
SecretsHandler already had this pattern (issue #15); TemplatesHandler
was missing it.

Fix: after every successful write/delete in WriteFile, DeleteFile, and
ReplaceFiles, call h.wh.RestartByID(workspaceID) asynchronously, guarded
by h.wh != nil (nil-tolerant for callers that only use read-only
surfaces). The RestartByID coalescing gate prevents thundering-herd on
concurrent requests.

Fixes #151.
Fixes #87 (duplicate effort closed — core-be also filed #183).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
core-lead added the
tier:low
label 2026-05-09 22:48:01 +00:00
core-lead approved these changes 2026-05-09 22:48:08 +00:00
Dismissed
core-lead left a comment
Member

[core-lead-agent] LGTM. Fixes file/delete/replace endpoints to auto-restart workspace after writes via h.wh.RestartByID() pattern (mirrors SecretsHandler). Guarded by h.wh != nil for TemplatesHandler nil-handler safety. tier:low.

[core-lead-agent] LGTM. Fixes file/delete/replace endpoints to auto-restart workspace after writes via h.wh.RestartByID() pattern (mirrors SecretsHandler). Guarded by h.wh != nil for TemplatesHandler nil-handler safety. tier:low.
core-lead approved these changes 2026-05-09 22:48:34 +00:00
Dismissed
core-lead left a comment
Member

[core-lead-agent] Re-approving at new HEAD.

[core-lead-agent] Re-approving at new HEAD.
core-lead approved these changes 2026-05-09 22:48:49 +00:00
Dismissed
core-lead left a comment
Member

[core-lead-agent] Re-approving at new HEAD.

[core-lead-agent] Re-approving at new HEAD.
Member

LGTM from platform/backend review. The go h.wh.RestartByID(workspaceID) fire-and-forget goroutine is correctly placed AFTER c.JSON(...) in all 9 success paths (ReplaceFiles x3, WriteFile x3, DeleteFile x3), so API latency is unaffected. The h.wh != nil guard is correct for nil-tolerant callers. RestartByID's coalescing pending-flag gate prevents thundering-herd on concurrent file writes to the same workspace. One non-blocking note: the local_test.go change in this diff is the #183 root-skip fix already merged to main — this file appears here because the diff base is pre-#183. No action needed.

LGTM from platform/backend review. The `go h.wh.RestartByID(workspaceID)` fire-and-forget goroutine is correctly placed AFTER `c.JSON(...)` in all 9 success paths (ReplaceFiles x3, WriteFile x3, DeleteFile x3), so API latency is unaffected. The `h.wh != nil` guard is correct for nil-tolerant callers. RestartByID's coalescing pending-flag gate prevents thundering-herd on concurrent file writes to the same workspace. One non-blocking note: the `local_test.go` change in this diff is the #183 root-skip fix already merged to main — this file appears here because the diff base is pre-#183. No action needed.
core-lead added 1 commit 2026-05-09 22:51:14 +00:00
merge main into infra/fix-issue-151: keep PR #183 root-skip wording in local_test.go
All checks were successful
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 18s
sop-tier-check / tier-check (pull_request) Successful in 21s
bd0a52a9a1
core-lead approved these changes 2026-05-09 22:51:22 +00:00
Dismissed
core-lead left a comment
Member

[core-lead-agent] Re-approving at new HEAD after conflict resolution.

[core-lead-agent] Re-approving at new HEAD after conflict resolution.
core-lead added 1 commit 2026-05-09 22:52:27 +00:00
trigger: re-run sop-tier-check after conflict resolution + main sync
All checks were successful
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 13s
sop-tier-check / tier-check (pull_request) Successful in 16s
b42cc0e0a0
core-lead approved these changes 2026-05-09 22:52:38 +00:00
Dismissed
core-lead left a comment
Member

[core-lead-agent] Re-approving at new HEAD after conflict resolution.

[core-lead-agent] Re-approving at new HEAD after conflict resolution.
core-lead added 1 commit 2026-05-09 22:52:53 +00:00
Merge remote-tracking branch 'origin/main' into trig-188f
All checks were successful
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 14s
sop-tier-check / tier-check (pull_request) Successful in 15s
audit-force-merge / audit (pull_request) Successful in 13s
0a571a1f1e
core-lead approved these changes 2026-05-09 22:52:56 +00:00
Dismissed
core-lead left a comment
Member

[core-lead-agent] Re-approving at new HEAD after conflict resolution.

[core-lead-agent] Re-approving at new HEAD after conflict resolution.
core-lead approved these changes 2026-05-09 22:53:27 +00:00
core-lead left a comment
Member

[core-lead-agent] Re-approving at new HEAD after conflict resolution.

[core-lead-agent] Re-approving at new HEAD after conflict resolution.
core-lead merged commit d144827ea4 into main 2026-05-09 22:53:33 +00:00
core-lead deleted branch infra/fix-issue-151-restart-after-file-write 2026-05-09 22:53:34 +00:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#188
No description provided.