// approved_run_copy_test.go package main import ( "fmt" "os" "path/filepath" "strconv" "strings" "testing" ) // The copy gate of the carlos run series (run Plan 1 Task 1). The deck is a // markdown table in the moves record's format, read with the moves gate's // parser and checked with its helpers, so "applied" means the same thing in // both gates: // // - TestRunCopyRecordIsComplete: the deck names exactly RUN-C1 to RUN-C87; // - TestRunBuiltCopyIsApproved: an id in runCopyBuilt is an approved row // (a string reaches code only after Paul has approved it); // - TestRunBuiltCopyIsApplied: a built row's text is in the file it names; // - TestRunCopyHasNoEmDash. const runCopyRecordPath = "docs/superpowers/plans/2026-10-08-carlos-run-copy.md" // runCopyIDs is the deck's inventory: RUN-C1 to RUN-C87, pinned. var runCopyIDs = func() []string { ids := make([]string, 0, 87) for i := 1; i <= 87; i++ { ids = append(ids, "RUN-C"+strconv.Itoa(i)) } return ids }() // runCopyBuilt is every deck id whose text the code or docs now carry. The // task that writes a row's text adds its id here in the same commit. var runCopyBuilt = []string{"RUN-C1", "RUN-C2", "RUN-C3", "RUN-C4", "RUN-C5", "RUN-C6", "RUN-C7", "RUN-C8", "RUN-C9", "RUN-C10", "RUN-C11", "RUN-C12", "RUN-C13", "RUN-C14", "RUN-C15", "RUN-C16", "RUN-C17", "RUN-C18", "RUN-C19", "RUN-C20", "RUN-C21", "RUN-C22", "RUN-C23", "RUN-C24", "RUN-C25", "RUN-C26", "RUN-C27", "RUN-C28", "RUN-C29", "RUN-C30", "RUN-C31", "RUN-C32", "RUN-C33", "RUN-C34", "RUN-C35", "RUN-C36", "RUN-C37", "RUN-C38", "RUN-C39", "RUN-C40", "RUN-C41", "RUN-C42", "RUN-C43", "RUN-C44", "RUN-C45", "RUN-C46", "RUN-C47", "RUN-C48", "RUN-C49", "RUN-C50", "RUN-C51", "RUN-C52", "RUN-C53", "RUN-C54", "RUN-C55", "RUN-C56", "RUN-C57", "RUN-C58", "RUN-C59", "RUN-C60", "RUN-C61", "RUN-C62", "RUN-C63", "RUN-C64", "RUN-C65", "RUN-C66", "RUN-C67", "RUN-C68", "RUN-C69", "RUN-C70", "RUN-C71", "RUN-C72", "RUN-C73", "RUN-C74", "RUN-C75", "RUN-C76", "RUN-C77", "RUN-C78", "RUN-C79", "RUN-C80", "RUN-C81", "RUN-C82", "RUN-C83", "RUN-C84", "RUN-C85", "RUN-C86", "RUN-C87"} func mustParseRunRecord(t *testing.T) []copyRow { t.Helper() rows, err := parseMovesCopyRecord(runCopyRecordPath) if err != nil { t.Fatal(err) } if len(rows) == 0 { t.Fatalf("%s has no rows", runCopyRecordPath) } for _, r := range rows { if !strings.HasPrefix(r.ID, "RUN-C") { t.Fatalf("%s: %s is not a RUN-C id", runCopyRecordPath, r.ID) } } return rows } // checkRunBuilt: every built id is named once, names a row, and that row is // approved. func checkRunBuilt(rows []copyRow, built []string) []string { byID := map[string]copyRow{} for _, r := range rows { byID[r.ID] = r } var out []string seen := map[string]bool{} for _, id := range built { if seen[id] { out = append(out, fmt.Sprintf("runCopyBuilt names %s twice", id)) } seen[id] = true r, ok := byID[id] switch { case !ok: out = append(out, fmt.Sprintf("runCopyBuilt names %s, which the deck has no row for", id)) case r.Status != "approved": out = append(out, fmt.Sprintf("%s is built but %s: a string reaches code only after Paul approves it", id, r.Status)) } } return out } // builtRows is the rows runCopyBuilt names, in deck order. func builtRows(rows []copyRow, built []string) []copyRow { want := map[string]bool{} for _, id := range built { want[id] = true } var out []copyRow for _, r := range rows { if want[r.ID] { out = append(out, r) } } return out } func TestRunCopyRecordIsComplete(t *testing.T) { reportAll(t, checkMovesInventory(mustParseRunRecord(t), runCopyIDs)) } func TestRunCopyHasNoEmDash(t *testing.T) { reportAll(t, checkMovesNoEmDash(mustParseRunRecord(t))) } func TestRunBuiltCopyIsApproved(t *testing.T) { reportAll(t, checkRunBuilt(mustParseRunRecord(t), runCopyBuilt)) } // runFragment reports whether a row's text is a piece of a larger literal // (its file cell says "a fragment"): the top-level usage text, which no // whole-expression match can find. func runFragment(r copyRow) bool { return strings.Contains(r.File, "(a fragment") } // checkRunApplied is checkMovesApplied, plus the fragment rows: those must // sit inside some string literal of their file (goLiteralMatches, // approved_copy_test.go), never only in a comment. func checkRunApplied(rows []copyRow, root string) []string { var whole []copyRow var out []string for _, r := range rows { if !runFragment(r) { whole = append(whole, r) continue } if r.Status != "approved" { continue } body, err := os.ReadFile(filepath.Join(root, r.Path())) if err != nil { out = append(out, fmt.Sprintf("%s: %v", r.ID, err)) continue } if !goLiteralMatches(body, func(v string) bool { return strings.Contains(v, r.Text) }) { out = append(out, fmt.Sprintf("%s: %s has no string literal holding the approved text %q", r.ID, r.Path(), r.Text)) } } return append(checkMovesApplied(whole, root), out...) } func TestRunBuiltCopyIsApplied(t *testing.T) { reportAll(t, checkRunApplied(builtRows(mustParseRunRecord(t), runCopyBuilt), ".")) } // Each fixture case is a state the gate must refuse, for the right reason. func TestRunCopyGateRefusesTheNegativeFixtures(t *testing.T) { dir := filepath.Join("testdata", "run-copy") rows, err := parseMovesCopyRecord(filepath.Join(dir, "record.md")) if err != nil { t.Fatal(err) } t.Run("a built row still pending", func(t *testing.T) { got := checkRunBuilt(rows, []string{"RUN-C2"}) if len(got) != 1 || !strings.Contains(got[0], "RUN-C2 is built but pending") { t.Errorf("problems = %q", got) } }) t.Run("a built id with no row", func(t *testing.T) { got := checkRunBuilt(rows, []string{"RUN-C9"}) if len(got) != 1 || !strings.Contains(got[0], "no row for") { t.Errorf("problems = %q", got) } }) t.Run("a built id named twice", func(t *testing.T) { got := checkRunBuilt(rows, []string{"RUN-C1", "RUN-C1"}) if len(got) != 1 || !strings.Contains(got[0], "twice") { t.Errorf("problems = %q", got) } }) t.Run("an approved row whose text is only in a comment", func(t *testing.T) { got := checkMovesApplied(builtRows(rows, []string{"RUN-C3"}), dir) if len(got) != 1 || !strings.Contains(got[0], "RUN-C3") { t.Errorf("problems = %q", got) } }) t.Run("an approved row that is applied", func(t *testing.T) { if got := checkRunApplied(builtRows(rows, []string{"RUN-C1"}), dir); len(got) != 0 { t.Errorf("problems = %q", got) } }) t.Run("a fragment inside a larger literal", func(t *testing.T) { if got := checkRunApplied(builtRows(rows, []string{"RUN-C4"}), dir); len(got) != 0 { t.Errorf("problems = %q", got) } }) t.Run("a fragment only in a comment", func(t *testing.T) { got := checkRunApplied(builtRows(rows, []string{"RUN-C5"}), dir) if len(got) != 1 || !strings.Contains(got[0], "RUN-C5") { t.Errorf("problems = %q", got) } }) } // The series is done only when every deck row is in the code or the docs. func TestRunCopyIsFullyBuilt(t *testing.T) { built := map[string]bool{} for _, id := range runCopyBuilt { built[id] = true } for _, id := range runCopyIDs { if !built[id] { t.Errorf("%s is in the deck but no task built it", id) } } }