← back to Cli Printing Press
fix(score): preserve spec extension, remove hardcoded repo path
98977f2371823c03ac3193a4aa6ebf9830c1de40 · 2026-03-27 21:50:14 -0700 · Trevin Chow
- copySpecToOutput now preserves the original file extension (.json,
.yaml, .yml) instead of always writing spec.json
- Skill no longer hardcodes ~/cli-printing-press — runs from the
current repo directory
- Spec resolution in skill checks for spec.json, spec.yaml, spec.yml
- Added tests for YAML/YML extension preservation and empty specFlag
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
M internal/pipeline/fullrun.goM internal/pipeline/fullrun_test.goM skills/printing-press-score/SKILL.md
Diff
commit 98977f2371823c03ac3193a4aa6ebf9830c1de40
Author: Trevin Chow <trevin@trevinchow.com>
Date: Fri Mar 27 21:50:14 2026 -0700
fix(score): preserve spec extension, remove hardcoded repo path
- copySpecToOutput now preserves the original file extension (.json,
.yaml, .yml) instead of always writing spec.json
- Skill no longer hardcodes ~/cli-printing-press — runs from the
current repo directory
- Spec resolution in skill checks for spec.json, spec.yaml, spec.yml
- Added tests for YAML/YML extension preservation and empty specFlag
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
internal/pipeline/fullrun.go | 10 ++++---
internal/pipeline/fullrun_test.go | 51 ++++++++++++++++++++++++++++--------
skills/printing-press-score/SKILL.md | 12 ++++-----
3 files changed, 53 insertions(+), 20 deletions(-)
diff --git a/internal/pipeline/fullrun.go b/internal/pipeline/fullrun.go
index 77204e96..09b2ec0c 100644
--- a/internal/pipeline/fullrun.go
+++ b/internal/pipeline/fullrun.go
@@ -422,8 +422,8 @@ func PrintComparisonTable(results []*FullRunResult) string {
return b.String()
}
-// copySpecToOutput copies the source spec file into <outputDir>/spec.json
-// so that standalone scoring can find it without the original spec path.
+// copySpecToOutput copies the source spec file into <outputDir>/spec.<ext>
+// preserving the original extension so YAML specs stay YAML and JSON stays JSON.
// Only copies when specFlag is "--spec" (local file). Errors are non-fatal.
func copySpecToOutput(specFlag, specURL, outputDir string) error {
if specFlag != "--spec" {
@@ -433,7 +433,11 @@ func copySpecToOutput(specFlag, specURL, outputDir string) error {
if err != nil {
return fmt.Errorf("reading spec %s: %w", specURL, err)
}
- dst := filepath.Join(outputDir, "spec.json")
+ ext := filepath.Ext(specURL)
+ if ext == "" {
+ ext = ".json"
+ }
+ dst := filepath.Join(outputDir, "spec"+ext)
if err := os.WriteFile(dst, data, 0o644); err != nil {
return fmt.Errorf("writing %s: %w", dst, err)
}
diff --git a/internal/pipeline/fullrun_test.go b/internal/pipeline/fullrun_test.go
index 5a8608db..7cd1d007 100644
--- a/internal/pipeline/fullrun_test.go
+++ b/internal/pipeline/fullrun_test.go
@@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "strings"
"testing"
"time"
@@ -67,18 +68,38 @@ func TestCopySpecToOutput(t *testing.T) {
name string
specFlag string
setup func(t *testing.T, dir string) string // returns specURL
- wantCopy bool
+ wantFile string // expected output filename
wantError bool
}{
{
- name: "copies spec when flag is --spec",
+ name: "copies json spec preserving extension",
specFlag: "--spec",
setup: func(t *testing.T, dir string) string {
specPath := filepath.Join(dir, "input-spec.json")
require.NoError(t, os.WriteFile(specPath, []byte(`{"openapi":"3.0.0"}`), 0o644))
return specPath
},
- wantCopy: true,
+ wantFile: "spec.json",
+ },
+ {
+ name: "copies yaml spec preserving extension",
+ specFlag: "--spec",
+ setup: func(t *testing.T, dir string) string {
+ specPath := filepath.Join(dir, "openapi.yaml")
+ require.NoError(t, os.WriteFile(specPath, []byte("openapi: 3.0.0\n"), 0o644))
+ return specPath
+ },
+ wantFile: "spec.yaml",
+ },
+ {
+ name: "copies yml spec preserving extension",
+ specFlag: "--spec",
+ setup: func(t *testing.T, dir string) string {
+ specPath := filepath.Join(dir, "api.yml")
+ require.NoError(t, os.WriteFile(specPath, []byte("openapi: 3.0.0\n"), 0o644))
+ return specPath
+ },
+ wantFile: "spec.yml",
},
{
name: "skips when flag is --docs",
@@ -86,7 +107,13 @@ func TestCopySpecToOutput(t *testing.T) {
setup: func(t *testing.T, dir string) string {
return "https://developers.notion.com/reference"
},
- wantCopy: false,
+ },
+ {
+ name: "skips when flag is empty",
+ specFlag: "",
+ setup: func(t *testing.T, dir string) string {
+ return ""
+ },
},
{
name: "returns error when spec file missing",
@@ -94,7 +121,6 @@ func TestCopySpecToOutput(t *testing.T) {
setup: func(t *testing.T, dir string) string {
return filepath.Join(dir, "nonexistent.json")
},
- wantCopy: false,
wantError: true,
},
}
@@ -114,15 +140,18 @@ func TestCopySpecToOutput(t *testing.T) {
assert.NoError(t, err)
}
- dst := filepath.Join(outputDir, "spec.json")
- if tt.wantCopy {
+ if tt.wantFile != "" {
+ dst := filepath.Join(outputDir, tt.wantFile)
data, readErr := os.ReadFile(dst)
- require.NoError(t, readErr, "spec.json should exist in output dir")
+ require.NoError(t, readErr, "%s should exist in output dir", tt.wantFile)
expected, _ := os.ReadFile(specURL)
- assert.Equal(t, expected, data, "spec.json content should match source")
+ assert.Equal(t, expected, data, "content should match source")
} else if !tt.wantError {
- _, readErr := os.ReadFile(dst)
- assert.True(t, os.IsNotExist(readErr), "spec.json should not exist")
+ // Verify no spec file was created
+ entries, _ := os.ReadDir(outputDir)
+ for _, e := range entries {
+ assert.False(t, strings.HasPrefix(e.Name(), "spec."), "no spec file should exist, found %s", e.Name())
+ }
}
})
}
diff --git a/skills/printing-press-score/SKILL.md b/skills/printing-press-score/SKILL.md
index 43121550..012ee41d 100644
--- a/skills/printing-press-score/SKILL.md
+++ b/skills/printing-press-score/SKILL.md
@@ -26,7 +26,7 @@ Score generated CLIs against the Steinberger bar. Supports rescoring, scoring by
## Prerequisites
- Go 1.21+ installed
-- The printing-press repo at ~/cli-printing-press
+- Running from inside the cli-printing-press repo (or a worktree of it)
## Step 1: Parse Arguments
@@ -77,7 +77,7 @@ If nothing resolves, report the error: "Could not find CLI '<name>'. Provide a p
For each resolved CLI directory, find the OpenAPI spec:
-1. Check `<cli-dir>/spec.json` — if it exists, use it
+1. Check for a spec file in `<cli-dir>/` — look for `spec.json`, `spec.yaml`, or `spec.yml` (the extension is preserved from the original spec during generation)
2. If not found, scan `docs/plans/*-pipeline/state.json` files for one matching this CLI's directory. Read its `spec_path` field. If that file exists on disk, use it.
3. If no spec found, **proceed without `--spec`**. Note to the user: "No spec found — Tier 2 (domain correctness) scores will be 0. Provide a spec path to get full scoring."
@@ -86,7 +86,7 @@ For each resolved CLI directory, find the OpenAPI spec:
Before running the scorecard, build the printing-press binary:
```bash
-cd ~/cli-printing-press && go build -o ./printing-press ./cmd/printing-press
+go build -o ./printing-press ./cmd/printing-press
```
If the build fails, report the error and stop.
@@ -98,7 +98,7 @@ If the build fails, report the error and stop.
Run the scorecard command:
```bash
-cd ~/cli-printing-press && ./printing-press scorecard --dir <resolved-path> --json
+./printing-press scorecard --dir <resolved-path> --json
```
If a spec was found, add `--spec <spec-path>`.
@@ -141,10 +141,10 @@ Run **both** scorecard commands in **parallel** using two simultaneous Bash tool
```bash
# Call 1:
-cd ~/cli-printing-press && ./printing-press scorecard --dir <path1> --spec <spec1> --json
+./printing-press scorecard --dir <path1> --spec <spec1> --json
# Call 2:
-cd ~/cli-printing-press && ./printing-press scorecard --dir <path2> --spec <spec2> --json
+./printing-press scorecard --dir <path2> --spec <spec2> --json
```
Parse both JSON outputs.
← 64e5ea58 refactor(scorecard): extract infra maps and add workflow/ins
·
back to Cli Printing Press
·
docs(scorecard): document intentional workflow/insight prefi 5ed49878 →