Reconcile docs with reality; fix module graph, token compare, health #1

Open
kami wants to merge 216 commits from webui-and-audit-reconciliation into master
2 changed files with 58 additions and 2 deletions
Showing only changes of commit 4b320809bd - Show all commits
+11 -2
View File
@@ -4,6 +4,7 @@
package orchestrator
import (
"bytes"
"context"
"encoding/json"
"errors"
@@ -88,10 +89,18 @@ func (w GitWorktrees) Create(ctx context.Context, t domain.Task) (string, error)
// clean, and so its hash survives independent of any later scratch commits.
func writeTaskFile(ctx context.Context, worktree string, t domain.Task) error {
path := filepath.Join(worktree, "TASK.md")
if _, err := os.Stat(path); err == nil {
want := continuity.RenderTaskFile(t)
// Presence is not identity. Delivery merges the task branch, and the
// branch carries this commit, so a later task's worktree branches from a
// master that already holds the *previous* task's TASK.md. Returning early
// on os.Stat left that file in place, and every immutability check then
// failed with "TASK.md changed" against a hash for a task nobody was
// running. Found live: run 7 died on retry_limit without ever leaving
// research.
if got, err := os.ReadFile(path); err == nil && bytes.Equal(got, want) {
return nil
}
if err := os.WriteFile(path, continuity.RenderTaskFile(t), 0644); err != nil {
if err := os.WriteFile(path, want, 0644); err != nil {
return err
}
for _, args := range [][]string{{"add", "TASK.md"}, {"commit", "-m", "orchestra: TASK.md"}} {
+47
View File
@@ -125,3 +125,50 @@ func TestGitWorktreesCommitsTaskFile(t *testing.T) {
t.Fatalf("TASK.md changed on recreate")
}
}
// A delivered task branch carries its own TASK.md, so master ends up holding
// the previous task's file. The next worktree must not inherit it: run 7 died
// on retry_limit because every release failed "TASK.md changed" against a hash
// for a task nobody was running.
func TestWorktreeReplacesAnInheritedTaskFile(t *testing.T) {
base := t.TempDir()
repo := filepath.Join(base, "repo")
initRepo(t, repo)
previous := domain.Task{ID: "previous-task", Project: "p", Title: "the merged one"}
if err := os.WriteFile(filepath.Join(repo, "TASK.md"), continuity.RenderTaskFile(previous), 0644); err != nil {
t.Fatal(err)
}
for _, args := range [][]string{{"add", "TASK.md"}, {"commit", "-m", "merged task branch"}} {
cmd := exec.Command("git", args...)
cmd.Dir = repo
cmd.Env = append(os.Environ(), "GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@t", "GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@t")
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("git %v: %v: %s", args, err, out)
}
}
current := domain.Task{ID: "current-task", Project: "p", Title: "the one being run"}
w := orchestrator.GitWorktrees{Root: filepath.Join(base, "wt"), Repo: repo}
path, err := w.Create(context.Background(), current)
if err != nil {
t.Fatalf("create: %v", err)
}
got, err := os.ReadFile(filepath.Join(path, "TASK.md"))
if err != nil {
t.Fatal(err)
}
if string(got) != string(continuity.RenderTaskFile(current)) {
t.Fatalf("worktree inherited a stale TASK.md:\n%s", got)
}
// Committed, not left dirty: the immutability check reads git status.
cmd := exec.Command("git", "status", "--porcelain")
cmd.Dir = path
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git status: %v: %s", err, out)
}
if strings.Contains(string(out), "TASK.md") {
t.Fatalf("TASK.md left uncommitted: %s", out)
}
}