parallax#1 was the real-world evidence: infra#179's branch-writability stall (>40s observed) blew past the tool's 5s budget, substitution ran zero files, and the repo shipped genuinely broken (go.mod still read `module __MODULE_PATH__`) — recoverable only via a manual clone/sed/git-mv/push. Adds `resume: bool`. When true, skips template lookup and repo generation entirely — the destination must already exist — and jumps straight to the tree-walk substitution. This is safe to re-invoke repeatedly because substituteEntry already compares against the branch's CURRENT state on every call (GetTree is re-fetched fresh each time): a file already fixed in a prior partial pass shows up already-correct or already-renamed and is a no-op. So the actual blocker to resumability was purely the "destination must NOT exist" guard on the create path — flipped it for resume, no change needed to the substitution logic itself. Consequences of resume existing: - infra179FinalizeMessage (#46) now points at the concrete recovery — "call this tool again with resume=true" — instead of manual clone/sed guidance. - "no placeholders substituted" only loud-fails on a FRESH create; on resume, finding nothing left to do is the expected steady state (success). - dispatch_allow injection (#43) is now idempotent (read-before-write, update with sha if present-but-different, skip if already correct) so a resumed call with dispatch_allow=true doesn't error re-creating a path that already exists (#51's root cause). - #51's other ask: dispatch_allow failures now land in their own dispatch_allow_failure field, never conflated with substitution's partial_failure — the two can independently succeed/fail. Tests: resume with no destination (error, names "nothing to resume"), resume continuing a partial substitution (asserts /generate is never re-called, only the still-wrong file is rewritten), resume when already fully done (success, not the fresh-create loud-fail), dispatch_allow idempotent re-injection (two-phase test capturing the real written content, no test-visible knowledge of the internal constant), and dispatch_allow_failure as a distinct field. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
24 lines
773 B
Go
24 lines
773 B
Go
package tools
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// #46: the infra#179 finalize guidance must not point at a non-existent command
|
|
// (`hyperguild new-project` was never built). #50 superseded the original
|
|
// manual-editing guidance with a concrete, real recovery: re-invoke this same
|
|
// tool with resume=true.
|
|
func TestInfra179FinalizeMessage(t *testing.T) {
|
|
msg := infra179FinalizeMessage("main", 5, 2, "branch does not exist")
|
|
|
|
for _, want := range []string{"infra#179", "resume=true", "branch does not exist"} {
|
|
if !strings.Contains(msg, want) {
|
|
t.Errorf("message missing %q\ngot: %s", want, msg)
|
|
}
|
|
}
|
|
if strings.Contains(msg, "hyperguild new-project") {
|
|
t.Errorf("message must not reference the defunct `hyperguild new-project` command\ngot: %s", msg)
|
|
}
|
|
}
|