[object Object]

← back to Cli Printing Press

refactor(cli): share generated naming helpers (#327)

52bde6b4336e9af38fd64d27e528f5e1935ca263 · 2026-04-26 20:29:24 -0700 · Trevin Chow

## Change: share generator/tools-manifest naming helpers

### Equivalence contract
- Inputs covered: template snake, envVarPlaceholder, oneline, mcpDescription, mcpDescriptionRich base behavior, and tools-manifest tool names/descriptions/header placeholders.
- Ordering preserved: yes. Call sites remain in the same loops and template execution order.
- Tie-breaking: unchanged; MCP auth annotation minority/tie behavior moved into the shared helper.
- Error semantics: unchanged; helpers are pure and return no errors.
- Laziness: unchanged.
- Short-circuit eval: unchanged for MCP description auth-annotation branches.
- Floating-point: N/A.
- RNG / hash order: unchanged; no maps added.
- Observable side-effects: generated files, tools-manifest JSON, scorecard/golden output are byte-identical.
- Type narrowing: N/A.
- Rerender behavior: N/A.

### Verification
- go fmt ./...
- go test ./internal/naming ./internal/generator ./internal/pipeline
- go test ./...
- go build -o ./printing-press ./cmd/printing-press
- go vet ./...
- golangci-lint run ./...
- scripts/golden.sh verify

No golden fixtures were updated.

LOC: repo Go LOC 84,578 -> 84,454 (-124).

Files touched

Diff

commit 52bde6b4336e9af38fd64d27e528f5e1935ca263
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sun Apr 26 20:29:24 2026 -0700

    refactor(cli): share generated naming helpers (#327)
    
    ## Change: share generator/tools-manifest naming helpers
    
    ### Equivalence contract
    - Inputs covered: template snake, envVarPlaceholder, oneline, mcpDescription, mcpDescriptionRich base behavior, and tools-manifest tool names/descriptions/header placeholders.
    - Ordering preserved: yes. Call sites remain in the same loops and template execution order.
    - Tie-breaking: unchanged; MCP auth annotation minority/tie behavior moved into the shared helper.
    - Error semantics: unchanged; helpers are pure and return no errors.
    - Laziness: unchanged.
    - Short-circuit eval: unchanged for MCP description auth-annotation branches.
    - Floating-point: N/A.
    - RNG / hash order: unchanged; no maps added.
    - Observable side-effects: generated files, tools-manifest JSON, scorecard/golden output are byte-identical.
    - Type narrowing: N/A.
    - Rerender behavior: N/A.
    
    ### Verification
    - go fmt ./...
    - go test ./internal/naming ./internal/generator ./internal/pipeline
    - go test ./...
    - go build -o ./printing-press ./cmd/printing-press
    - go vet ./...
    - golangci-lint run ./...
    - scripts/golden.sh verify
    
    No golden fixtures were updated.
    
    LOC: repo Go LOC 84,578 -> 84,454 (-124).
---
 internal/generator/generator.go         |  96 +++--------------------
 internal/generator/generator_test.go    |   2 +-
 internal/generator/plan_generate.go     |   2 +-
 internal/naming/naming.go               |  78 +++++++++++++++++++
 internal/naming/naming_test.go          |  89 ++++++++++++++++++++-
 internal/pipeline/toolsmanifest.go      |  91 ++--------------------
 internal/pipeline/toolsmanifest_test.go | 132 --------------------------------
 7 files changed, 183 insertions(+), 307 deletions(-)

diff --git a/internal/generator/generator.go b/internal/generator/generator.go
index 82cee2e5..ba8ad6a7 100644
--- a/internal/generator/generator.go
+++ b/internal/generator/generator.go
@@ -166,7 +166,7 @@ func New(s *spec.APISpec, outputDir string) *Generator {
 		"upper":                 strings.ToUpper,
 		"join":                  strings.Join,
 		"camel":                 toCamel,
-		"snake":                 toSnake,
+		"snake":                 naming.Snake,
 		"pascal":                toPascal,
 		"goType":                goType,
 		"goStructType":          goStructType,
@@ -190,13 +190,13 @@ func New(s *spec.APISpec, outputDir string) *Generator {
 		"columnPlaceholders":     columnPlaceholders,
 		"updateSet":              updateSet,
 		"envVarField":            envVarField,
-		"envVarPlaceholder":      envVarPlaceholder,
+		"envVarPlaceholder":      naming.EnvVarPlaceholder,
 		"envVarIsBuiltinField":   envVarIsBuiltinField,
 		"envVarBuiltinFieldName": envVarBuiltinFieldName,
 		"resolveEnvVarField":     resolveEnvVarField,
 		"add":                    func(a, b int) int { return a + b },
-		"oneline":                oneline,
-		"mcpDescription":         mcpDescription,
+		"oneline":                naming.OneLine,
+		"mcpDescription":         naming.MCPDescription,
 		"mcpDescriptionRich":     mcpDescriptionRich,
 		"flagName":               flagName,
 		"paramIdent":             paramIdent,
@@ -776,7 +776,7 @@ func safeDisplayURL(value string) string {
 func (g *Generator) buildDomainContext() DomainContext {
 	ctx := DomainContext{
 		APIName:     g.Spec.Name,
-		Description: oneline(g.Spec.Description),
+		Description: naming.OneLine(g.Spec.Description),
 		Archetype:   string(profiler.ArchetypeGeneric),
 	}
 
@@ -792,7 +792,7 @@ func (g *Generator) buildDomainContext() DomainContext {
 		for rName, r := range g.Spec.Resources {
 			rs := ResourceSummary{
 				Name:        rName,
-				Description: oneline(r.Description),
+				Description: naming.OneLine(r.Description),
 				Syncable:    syncSet[rName],
 				Searchable:  len(g.profile.SearchableFields[rName]) > 0,
 			}
@@ -1809,17 +1809,6 @@ func toCamel(s string) string {
 	return result
 }
 
-func toSnake(s string) string {
-	var result strings.Builder
-	for i, r := range s {
-		if unicode.IsUpper(r) && i > 0 {
-			result.WriteRune('_')
-		}
-		result.WriteRune(unicode.ToLower(r))
-	}
-	return result.String()
-}
-
 func toPascal(s string) string {
 	parts := strings.FieldsFunc(s, func(r rune) bool {
 		return r == '_' || r == '-' || !unicode.IsLetter(r) && !unicode.IsDigit(r)
@@ -2284,7 +2273,7 @@ var builtinConfigTags = map[string]string{
 // envVarIsBuiltinField returns true if the env var's placeholder tag would
 // collide with a hardcoded Config struct field tag.
 func envVarIsBuiltinField(envVar string) bool {
-	placeholder := envVarPlaceholder(envVar)
+	placeholder := naming.EnvVarPlaceholder(envVar)
 	_, ok := builtinConfigTags[placeholder]
 	return ok
 }
@@ -2292,7 +2281,7 @@ func envVarIsBuiltinField(envVar string) bool {
 // envVarBuiltinFieldName returns the Go field name of the hardcoded Config
 // struct field that matches this env var's placeholder, or empty string if none.
 func envVarBuiltinFieldName(envVar string) string {
-	placeholder := envVarPlaceholder(envVar)
+	placeholder := naming.EnvVarPlaceholder(envVar)
 	return builtinConfigTags[placeholder]
 }
 
@@ -2307,65 +2296,12 @@ func resolveEnvVarField(envVar string) string {
 	return envVarField(envVar)
 }
 
-func oneline(s string) string {
-	s = strings.ReplaceAll(s, "\r\n", " ")
-	s = strings.ReplaceAll(s, "\n", " ")
-	s = strings.ReplaceAll(s, "\r", " ")
-	s = strings.ReplaceAll(s, `"`, `'`)
-	s = strings.ReplaceAll(s, "\\", "")
-	for strings.Contains(s, "  ") {
-		s = strings.ReplaceAll(s, "  ", " ")
-	}
-	s = strings.TrimSpace(s)
-	if len(s) > 120 {
-		cut := s[:117]
-		if idx := strings.LastIndex(cut, " "); idx > 60 {
-			s = cut[:idx] + "..."
-		} else {
-			s = cut + "..."
-		}
-	}
-	return s
-}
-
-// mcpDescription builds an MCP tool description with optional minority-side
-// auth annotation. Only annotates when the CLI has a mix of public and
-// auth-required tools. The minority side gets annotated:
-//   - Public is minority → append "(public)"
-//   - Auth-required is minority → append auth-type-specific suffix
-//   - All same status or exact tie → no annotation
-func mcpDescription(desc string, noAuth bool, authType string, publicCount, totalCount int) string {
-	authCount := totalCount - publicCount
-	mixed := publicCount > 0 && authCount > 0
-
-	if mixed {
-		if noAuth && publicCount < authCount {
-			// Public endpoints are the minority — mark them
-			desc = desc + " (public)"
-		} else if !noAuth && authCount < publicCount {
-			// Auth-required endpoints are the minority — mark them
-			switch authType {
-			case "api_key":
-				desc = desc + " (requires API key)"
-			case "cookie", "composed":
-				desc = desc + " (requires browser login)"
-			case "oauth2", "bearer_token":
-				desc = desc + " (requires auth)"
-			default:
-				desc = desc + " (requires auth)"
-			}
-		}
-	}
-
-	return oneline(desc)
-}
-
 // mcpDescriptionRich builds an enriched MCP tool description that includes
 // the base description plus response shape hints and method context.
 // This gives agents enough information to choose the right tool without
 // trial-and-error. Total length is capped to prevent token bloat.
 func mcpDescriptionRich(desc string, noAuth bool, authType string, publicCount, totalCount int, method, respType, respItem string) string {
-	base := mcpDescription(desc, noAuth, authType, publicCount, totalCount)
+	base := naming.MCPDescription(desc, noAuth, authType, publicCount, totalCount)
 
 	var suffix string
 
@@ -2670,20 +2606,6 @@ func sortedEndpointNames(endpoints map[string]spec.Endpoint) []string {
 	return names
 }
 
-func envVarPlaceholder(envVar string) string {
-	// STYTCH_PROJECT_ID -> project_id (the placeholder in the format string)
-	parts := strings.Split(envVar, "_")
-	if len(parts) <= 1 {
-		return strings.ToLower(envVar)
-	}
-	// Skip the first part (tool name prefix) and join the rest
-	var lower []string
-	for _, p := range parts[1:] {
-		lower = append(lower, strings.ToLower(p))
-	}
-	return strings.Join(lower, "_")
-}
-
 // isGraphQLSpec returns true if the spec was produced by a GraphQL SDL parser.
 // Detection heuristic: all list endpoints have path "/graphql".
 func isGraphQLSpec(s *spec.APISpec) bool {
diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go
index 29e9c2ad..97a5adda 100644
--- a/internal/generator/generator_test.go
+++ b/internal/generator/generator_test.go
@@ -2965,7 +2965,7 @@ func TestMCPDescription(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			t.Parallel()
-			got := mcpDescription(tt.desc, tt.noAuth, tt.authType, tt.publicCount, tt.totalCount)
+			got := naming.MCPDescription(tt.desc, tt.noAuth, tt.authType, tt.publicCount, tt.totalCount)
 			assert.Equal(t, tt.want, got)
 		})
 	}
diff --git a/internal/generator/plan_generate.go b/internal/generator/plan_generate.go
index 7f6764cf..874e440e 100644
--- a/internal/generator/plan_generate.go
+++ b/internal/generator/plan_generate.go
@@ -81,7 +81,7 @@ func GenerateFromPlan(planSpec *PlanSpec, outputDir string) error {
 		"upper":       strings.ToUpper,
 		"pascal":      toPascal,
 		"camel":       toCamel,
-		"snake":       toSnake,
+		"snake":       naming.Snake,
 		"kebab":       toKebab,
 		"currentYear": func() string { return strconv.Itoa(time.Now().Year()) },
 		"modulePath":  func() string { return naming.CLI(cliName) },
diff --git a/internal/naming/naming.go b/internal/naming/naming.go
index b75ea278..3d3b0524 100644
--- a/internal/naming/naming.go
+++ b/internal/naming/naming.go
@@ -66,6 +66,84 @@ func EnvPrefix(name string) string {
 	return out
 }
 
+// Snake converts CamelCase to snake_case for generated tool name segments.
+// Hyphens are intentionally preserved to match the historical MCP template
+// helper behavior.
+func Snake(s string) string {
+	var result strings.Builder
+	for i, r := range s {
+		if unicode.IsUpper(r) && i > 0 {
+			result.WriteRune('_')
+		}
+		result.WriteRune(unicode.ToLower(r))
+	}
+	return result.String()
+}
+
+// EnvVarPlaceholder derives the placeholder name from an environment variable.
+// DUB_TOKEN -> token, STYTCH_PROJECT_ID -> project_id.
+func EnvVarPlaceholder(envVar string) string {
+	parts := strings.Split(envVar, "_")
+	if len(parts) <= 1 {
+		return strings.ToLower(envVar)
+	}
+	lower := make([]string, 0, len(parts)-1)
+	for _, p := range parts[1:] {
+		lower = append(lower, strings.ToLower(p))
+	}
+	return strings.Join(lower, "_")
+}
+
+// OneLine normalizes generated descriptions for compact template and manifest
+// output.
+func OneLine(s string) string {
+	s = strings.ReplaceAll(s, "\r\n", " ")
+	s = strings.ReplaceAll(s, "\n", " ")
+	s = strings.ReplaceAll(s, "\r", " ")
+	s = strings.ReplaceAll(s, `"`, `'`)
+	s = strings.ReplaceAll(s, "\\", "")
+	for strings.Contains(s, "  ") {
+		s = strings.ReplaceAll(s, "  ", " ")
+	}
+	s = strings.TrimSpace(s)
+	if len(s) > 120 {
+		cut := s[:117]
+		if idx := strings.LastIndex(cut, " "); idx > 60 {
+			s = cut[:idx] + "..."
+		} else {
+			s = cut + "..."
+		}
+	}
+	return s
+}
+
+// MCPDescription builds an MCP tool description with optional minority-side
+// auth annotation. It annotates only when an API has a mix of public and
+// auth-required tools, and only the minority side gets annotated.
+func MCPDescription(desc string, noAuth bool, authType string, publicCount, totalCount int) string {
+	authCount := totalCount - publicCount
+	mixed := publicCount > 0 && authCount > 0
+
+	if mixed {
+		if noAuth && publicCount < authCount {
+			desc = desc + " (public)"
+		} else if !noAuth && authCount < publicCount {
+			switch authType {
+			case "api_key":
+				desc = desc + " (requires API key)"
+			case "cookie", "composed":
+				desc = desc + " (requires browser login)"
+			case "oauth2", "bearer_token":
+				desc = desc + " (requires auth)"
+			default:
+				desc = desc + " (requires auth)"
+			}
+		}
+	}
+
+	return OneLine(desc)
+}
+
 func DogfoodBinary(name string) string {
 	return CLI(name) + "-dogfood"
 }
diff --git a/internal/naming/naming_test.go b/internal/naming/naming_test.go
index ba838d64..86bfa127 100644
--- a/internal/naming/naming_test.go
+++ b/internal/naming/naming_test.go
@@ -1,6 +1,9 @@
 package naming
 
-import "testing"
+import (
+	"strings"
+	"testing"
+)
 
 func TestTrimCLISuffix(t *testing.T) {
 	tests := map[string]string{
@@ -67,6 +70,90 @@ func TestEnvPrefix(t *testing.T) {
 	}
 }
 
+func TestSnake(t *testing.T) {
+	tests := map[string]string{
+		"Pets":          "pets",
+		"GetInventory":  "get_inventory",
+		"List":          "list",
+		"PublicList":    "public_list",
+		"APIKeys":       "a_p_i_keys",
+		"simple":        "simple",
+		"already_snake": "already_snake",
+		"with-hyphen":   "with-hyphen",
+	}
+
+	for input, want := range tests {
+		if got := Snake(input); got != want {
+			t.Fatalf("Snake(%q) = %q, want %q", input, got, want)
+		}
+	}
+}
+
+func TestEnvVarPlaceholder(t *testing.T) {
+	tests := map[string]string{
+		"DUB_TOKEN":         "token",
+		"STYTCH_PROJECT_ID": "project_id",
+		"STEAM_WEB_API_KEY": "web_api_key",
+		"TOKEN":             "token",
+		"GITHUB_TOKEN":      "token",
+	}
+
+	for input, want := range tests {
+		if got := EnvVarPlaceholder(input); got != want {
+			t.Fatalf("EnvVarPlaceholder(%q) = %q, want %q", input, got, want)
+		}
+	}
+}
+
+func TestOneLine(t *testing.T) {
+	tests := map[string]string{
+		"line one\nline two": "line one line two",
+		"too  many   spaces": "too many spaces",
+		`say "hello"`:        "say 'hello'",
+		"  spaces  ":         "spaces",
+	}
+
+	for input, want := range tests {
+		if got := OneLine(input); got != want {
+			t.Fatalf("OneLine(%q) = %q, want %q", input, got, want)
+		}
+	}
+
+	if got := OneLine(string(make([]byte, 200))); len(got) > 120 {
+		t.Fatalf("OneLine(long string) length = %d, want <= 120", len(got))
+	}
+}
+
+func TestMCPDescription(t *testing.T) {
+	tests := []struct {
+		name        string
+		desc        string
+		noAuth      bool
+		authType    string
+		publicCount int
+		totalCount  int
+		wantSuffix  string
+	}{
+		{"public minority gets annotated", "List items", true, "api_key", 2, 10, "(public)"},
+		{"auth minority gets api key annotation", "Create item", false, "api_key", 8, 10, "(requires API key)"},
+		{"auth minority gets cookie annotation", "Create item", false, "cookie", 8, 10, "(requires browser login)"},
+		{"all auth has no annotation", "Create item", false, "api_key", 0, 10, ""},
+		{"all public has no annotation", "List items", true, "api_key", 10, 10, ""},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := MCPDescription(tt.desc, tt.noAuth, tt.authType, tt.publicCount, tt.totalCount)
+			if tt.wantSuffix != "" && !strings.Contains(got, tt.wantSuffix) {
+				t.Fatalf("MCPDescription() = %q, want suffix %q", got, tt.wantSuffix)
+			}
+			if tt.wantSuffix == "" && (strings.Contains(got, "(public)") || strings.Contains(got, "(requires")) {
+				t.Fatalf("MCPDescription() = %q, want no auth annotation", got)
+			}
+		})
+	}
+}
+
 func TestIsCLIDirName(t *testing.T) {
 	if !IsCLIDirName("stripe-pp-cli-3") {
 		t.Fatal("expected suffixed pp-cli directory to be recognized")
diff --git a/internal/pipeline/toolsmanifest.go b/internal/pipeline/toolsmanifest.go
index 0bdbc0c6..9f63685c 100644
--- a/internal/pipeline/toolsmanifest.go
+++ b/internal/pipeline/toolsmanifest.go
@@ -9,8 +9,8 @@ import (
 	"path/filepath"
 	"sort"
 	"strings"
-	"unicode"
 
+	"github.com/mvanhorn/cli-printing-press/v2/internal/naming"
 	"github.com/mvanhorn/cli-printing-press/v2/internal/spec"
 )
 
@@ -131,8 +131,8 @@ func WriteToolsManifest(dir string, parsed *spec.APISpec) error {
 			if cookieOrComposed && !endpoint.NoAuth {
 				continue
 			}
-			toolName := toolSnake(rName) + "_" + toolSnake(eName)
-			desc := mcpDescriptionForManifest(endpoint.Description, endpoint.NoAuth, parsed.Auth.Type, public, total)
+			toolName := naming.Snake(rName) + "_" + naming.Snake(eName)
+			desc := naming.MCPDescription(endpoint.Description, endpoint.NoAuth, parsed.Auth.Type, public, total)
 			tool := buildManifestTool(toolName, desc, endpoint)
 			manifest.Tools = append(manifest.Tools, tool)
 		}
@@ -147,8 +147,8 @@ func WriteToolsManifest(dir string, parsed *spec.APISpec) error {
 				if cookieOrComposed && !endpoint.NoAuth {
 					continue
 				}
-				toolName := toolSnake(rName) + "_" + toolSnake(subName) + "_" + toolSnake(eName)
-				desc := mcpDescriptionForManifest(endpoint.Description, endpoint.NoAuth, parsed.Auth.Type, public, total)
+				toolName := naming.Snake(rName) + "_" + naming.Snake(subName) + "_" + naming.Snake(eName)
+				desc := naming.MCPDescription(endpoint.Description, endpoint.NoAuth, parsed.Auth.Type, public, total)
 				tool := buildManifestTool(toolName, desc, endpoint)
 				manifest.Tools = append(manifest.Tools, tool)
 			}
@@ -230,7 +230,7 @@ func normalizeAuthFormat(format string, envVars []string) string {
 	}
 	result := format
 	for _, envVar := range envVars {
-		derived := envVarPlaceholder(envVar)
+		derived := naming.EnvVarPlaceholder(envVar)
 		if derived != strings.ToLower(envVar) {
 			// Replace the derived placeholder with the env var name.
 			result = strings.ReplaceAll(result, "{"+derived+"}", "{"+envVar+"}")
@@ -247,21 +247,6 @@ func normalizeAuthFormat(format string, envVars []string) string {
 	return result
 }
 
-// envVarPlaceholder derives the placeholder name from an env var.
-// DUB_TOKEN -> token, STYTCH_PROJECT_ID -> project_id.
-// Mirrors the logic in internal/generator/generator.go:1331.
-func envVarPlaceholder(envVar string) string {
-	parts := strings.Split(envVar, "_")
-	if len(parts) <= 1 {
-		return strings.ToLower(envVar)
-	}
-	lower := make([]string, 0, len(parts)-1)
-	for _, p := range parts[1:] {
-		lower = append(lower, strings.ToLower(p))
-	}
-	return strings.Join(lower, "_")
-}
-
 // normalizeParamType ensures a consistent type string. Empty types default
 // to "string".
 func normalizeParamType(t string) string {
@@ -271,70 +256,6 @@ func normalizeParamType(t string) string {
 	return t
 }
 
-// toolSnake converts CamelCase to snake_case for tool name segments.
-// This is a copy of toSnake from internal/generator/generator.go:794.
-// It does NOT convert hyphens, matching the MCP template's {{snake}} function.
-func toolSnake(s string) string {
-	var result strings.Builder
-	for i, r := range s {
-		if unicode.IsUpper(r) && i > 0 {
-			result.WriteRune('_')
-		}
-		result.WriteRune(unicode.ToLower(r))
-	}
-	return result.String()
-}
-
-// mcpDescriptionForManifest replicates the mcpDescription template function
-// from internal/generator/generator.go:1078 — adds minority-side annotations
-// for mixed auth/no-auth APIs.
-func mcpDescriptionForManifest(desc string, noAuth bool, authType string, publicCount, totalCount int) string {
-	authCount := totalCount - publicCount
-	mixed := publicCount > 0 && authCount > 0
-
-	if mixed {
-		if noAuth && publicCount < authCount {
-			desc = desc + " (public)"
-		} else if !noAuth && authCount < publicCount {
-			switch authType {
-			case "api_key":
-				desc = desc + " (requires API key)"
-			case "cookie", "composed":
-				desc = desc + " (requires browser login)"
-			case "oauth2", "bearer_token":
-				desc = desc + " (requires auth)"
-			default:
-				desc = desc + " (requires auth)"
-			}
-		}
-	}
-
-	return onelineForManifest(desc)
-}
-
-// onelineForManifest replicates the oneline template function from
-// internal/generator/generator.go:1051.
-func onelineForManifest(s string) string {
-	s = strings.ReplaceAll(s, "\r\n", " ")
-	s = strings.ReplaceAll(s, "\n", " ")
-	s = strings.ReplaceAll(s, "\r", " ")
-	s = strings.ReplaceAll(s, `"`, `'`)
-	s = strings.ReplaceAll(s, "\\", "")
-	for strings.Contains(s, "  ") {
-		s = strings.ReplaceAll(s, "  ", " ")
-	}
-	s = strings.TrimSpace(s)
-	if len(s) > 120 {
-		cut := s[:117]
-		if idx := strings.LastIndex(cut, " "); idx > 60 {
-			s = cut[:idx] + "..."
-		} else {
-			s = cut + "..."
-		}
-	}
-	return s
-}
-
 // sortedResourceKeys returns sorted keys from a map[string]spec.Resource.
 func sortedResourceKeys(m map[string]spec.Resource) []string {
 	keys := make([]string, 0, len(m))
diff --git a/internal/pipeline/toolsmanifest_test.go b/internal/pipeline/toolsmanifest_test.go
index 7c9ad30f..7b226509 100644
--- a/internal/pipeline/toolsmanifest_test.go
+++ b/internal/pipeline/toolsmanifest_test.go
@@ -740,96 +740,6 @@ func TestWriteToolsManifest_EmptyParamType(t *testing.T) {
 	assert.Equal(t, "string", got.Tools[0].Params[0].Type, "empty type should default to string")
 }
 
-func TestToolSnake(t *testing.T) {
-	tests := []struct {
-		input string
-		want  string
-	}{
-		{"Pets", "pets"},
-		{"GetInventory", "get_inventory"},
-		{"List", "list"},
-		{"PublicList", "public_list"},
-		{"APIKeys", "a_p_i_keys"}, // mirrors toSnake behavior for consecutive caps
-		{"simple", "simple"},
-		{"already_snake", "already_snake"},
-		{"with-hyphen", "with-hyphen"}, // does NOT convert hyphens
-	}
-	for _, tt := range tests {
-		t.Run(tt.input, func(t *testing.T) {
-			assert.Equal(t, tt.want, toolSnake(tt.input))
-		})
-	}
-}
-
-func TestMcpDescriptionForManifest(t *testing.T) {
-	tests := []struct {
-		name        string
-		desc        string
-		noAuth      bool
-		authType    string
-		publicCount int
-		totalCount  int
-		wantSuffix  string
-	}{
-		{
-			name:        "public minority gets annotated",
-			desc:        "List items",
-			noAuth:      true,
-			authType:    "api_key",
-			publicCount: 2,
-			totalCount:  10,
-			wantSuffix:  "(public)",
-		},
-		{
-			name:        "auth minority gets annotated with api_key",
-			desc:        "Create item",
-			noAuth:      false,
-			authType:    "api_key",
-			publicCount: 8,
-			totalCount:  10,
-			wantSuffix:  "(requires API key)",
-		},
-		{
-			name:        "auth minority gets annotated with cookie",
-			desc:        "Create item",
-			noAuth:      false,
-			authType:    "cookie",
-			publicCount: 8,
-			totalCount:  10,
-			wantSuffix:  "(requires browser login)",
-		},
-		{
-			name:        "no annotation when all auth",
-			desc:        "Create item",
-			noAuth:      false,
-			authType:    "api_key",
-			publicCount: 0,
-			totalCount:  10,
-			wantSuffix:  "",
-		},
-		{
-			name:        "no annotation when all public",
-			desc:        "List items",
-			noAuth:      true,
-			authType:    "api_key",
-			publicCount: 10,
-			totalCount:  10,
-			wantSuffix:  "",
-		},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			result := mcpDescriptionForManifest(tt.desc, tt.noAuth, tt.authType, tt.publicCount, tt.totalCount)
-			if tt.wantSuffix != "" {
-				assert.Contains(t, result, tt.wantSuffix)
-			} else {
-				assert.NotContains(t, result, "(public)")
-				assert.NotContains(t, result, "(requires")
-			}
-		})
-	}
-}
-
 func TestNormalizeAuthFormat(t *testing.T) {
 	tests := []struct {
 		name    string
@@ -887,45 +797,3 @@ func TestNormalizeAuthFormat(t *testing.T) {
 		})
 	}
 }
-
-func TestEnvVarPlaceholder(t *testing.T) {
-	tests := []struct {
-		input string
-		want  string
-	}{
-		{"DUB_TOKEN", "token"},
-		{"STYTCH_PROJECT_ID", "project_id"},
-		{"STEAM_WEB_API_KEY", "web_api_key"},
-		{"TOKEN", "token"},
-		{"GITHUB_TOKEN", "token"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.input, func(t *testing.T) {
-			assert.Equal(t, tt.want, envVarPlaceholder(tt.input))
-		})
-	}
-}
-
-func TestOnelineForManifest(t *testing.T) {
-	tests := []struct {
-		name  string
-		input string
-		want  string
-	}{
-		{"newlines collapsed", "line one\nline two", "line one line two"},
-		{"double spaces collapsed", "too  many   spaces", "too many spaces"},
-		{"quotes replaced", `say "hello"`, "say 'hello'"},
-		{"long string truncated", string(make([]byte, 200)), ""},
-		{"trimmed", "  spaces  ", "spaces"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			result := onelineForManifest(tt.input)
-			if tt.name == "long string truncated" {
-				assert.LessOrEqual(t, len(result), 120)
-			} else {
-				assert.Equal(t, tt.want, result)
-			}
-		})
-	}
-}

← a2fe1581 refactor(cli): simplify scorecard dimension bookkeeping (#32  ·  back to Cli Printing Press  ·  fix(ci): include refactors in release notes (#328) df551b37 →