← back to Cli Printing Press
fix(cli): resolveManuscripts prefers API-slug keying over CLI-name (#615)
700e4672f8ad937101cb21af893136badb2eb4e1 · 2026-05-05 08:24:51 -0700 · Trevin Chow
* fix(cli): resolveManuscripts prefers API-slug keying over CLI-name
Swap the lookup order in resolveManuscripts so the API-slug key (the SKILL's
archive convention) is consulted before the CLI-name key (legacy binary
convention). Refresh the lookup-branch comments to match. Reprints now
publish manuscripts from their actual run instead of stale runs that
happen to live under the CLI-name directory.
Update TestManuscriptLookupPriority to call resolveManuscripts directly
(via PRINTING_PRESS_HOME override) and add the cal-com regression subtest
covering the both-keys-present scenario from the parent retro.
The inline warn-only manuscripts lookup in runValidation (publish.go:621-628)
intentionally retains the old order per the upstream issue's scope boundary;
aligning it is deferred to follow-up work.
Refs #598 (parent retro #597 F2)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(cli): tighten resolveManuscripts test helpers
- Reuse pipeline.PublishedManuscriptsRoot() in withManuscriptsRoot instead
of duplicating the "manuscripts" path segment, so the helper stays
coupled to the production path function.
- Drop the unused "steam" fuzzy-fixture from the API-vs-CLI priority
subtest; that subtest doesn't exercise the fuzzy fallback.
- Trim the F2-regression block comment.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(cli): expand resolveManuscripts coverage and tidy comments
Address ce-code-review findings on the resolveManuscripts change:
- Drop ticket-number references from test comments per AGENTS.md
("no ticket numbers in code comments").
- Cover the apiName=="" guard branch via a subtest that relies on
TrimCLISuffix to derive the API slug from the CLI name.
- Cover the empty manuscripts root scenario the plan U1 enumerated
but the prior subtests left unreached.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Files touched
A docs/plans/2026-05-05-001-fix-resolve-manuscripts-api-slug-priority-plan.mdM internal/cli/publish.goM internal/cli/publish_resolve_test.go
Diff
commit 700e4672f8ad937101cb21af893136badb2eb4e1
Author: Trevin Chow <trevin@trevinchow.com>
Date: Tue May 5 08:24:51 2026 -0700
fix(cli): resolveManuscripts prefers API-slug keying over CLI-name (#615)
* fix(cli): resolveManuscripts prefers API-slug keying over CLI-name
Swap the lookup order in resolveManuscripts so the API-slug key (the SKILL's
archive convention) is consulted before the CLI-name key (legacy binary
convention). Refresh the lookup-branch comments to match. Reprints now
publish manuscripts from their actual run instead of stale runs that
happen to live under the CLI-name directory.
Update TestManuscriptLookupPriority to call resolveManuscripts directly
(via PRINTING_PRESS_HOME override) and add the cal-com regression subtest
covering the both-keys-present scenario from the parent retro.
The inline warn-only manuscripts lookup in runValidation (publish.go:621-628)
intentionally retains the old order per the upstream issue's scope boundary;
aligning it is deferred to follow-up work.
Refs #598 (parent retro #597 F2)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(cli): tighten resolveManuscripts test helpers
- Reuse pipeline.PublishedManuscriptsRoot() in withManuscriptsRoot instead
of duplicating the "manuscripts" path segment, so the helper stays
coupled to the production path function.
- Drop the unused "steam" fuzzy-fixture from the API-vs-CLI priority
subtest; that subtest doesn't exercise the fuzzy fallback.
- Trim the F2-regression block comment.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(cli): expand resolveManuscripts coverage and tidy comments
Address ce-code-review findings on the resolveManuscripts change:
- Drop ticket-number references from test comments per AGENTS.md
("no ticket numbers in code comments").
- Cover the apiName=="" guard branch via a subtest that relies on
TrimCLISuffix to derive the API slug from the CLI name.
- Cover the empty manuscripts root scenario the plan U1 enumerated
but the prior subtests left unreached.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
...x-resolve-manuscripts-api-slug-priority-plan.md | 165 +++++++++++++++++++++
internal/cli/publish.go | 15 +-
internal/cli/publish_resolve_test.go | 110 ++++++++------
3 files changed, 238 insertions(+), 52 deletions(-)
diff --git a/docs/plans/2026-05-05-001-fix-resolve-manuscripts-api-slug-priority-plan.md b/docs/plans/2026-05-05-001-fix-resolve-manuscripts-api-slug-priority-plan.md
new file mode 100644
index 00000000..edc559f0
--- /dev/null
+++ b/docs/plans/2026-05-05-001-fix-resolve-manuscripts-api-slug-priority-plan.md
@@ -0,0 +1,165 @@
+---
+title: "fix(cli): resolveManuscripts prefers API-slug keying over CLI-name"
+type: fix
+status: active
+date: 2026-05-05
+origin: https://github.com/mvanhorn/cli-printing-press/issues/598
+---
+
+# fix(cli): resolveManuscripts prefers API-slug keying over CLI-name
+
+## Summary
+
+Swap the lookup order in `resolveManuscripts` so the API-slug key (the SKILL's archive convention) is consulted before the CLI-name key (legacy binary convention), and refresh the stale "new convention" / "old convention" comments to match. Update the existing `TestManuscriptLookupPriority` fixture to assert the new priority and add the cal-com regression scenario. Reprints will now publish manuscripts from their actual run, not stale ones keyed under the binary name.
+
+---
+
+## Problem Frame
+
+`resolveManuscripts` in `internal/cli/publish.go` was authored when the printing-press binary archived manuscripts under `manuscripts/<cli-name>/`. The SKILL has since standardized on `$PRESS_MANUSCRIPTS/<api-slug>/<run-id>/` as the durable archive convention (SKILL.md lines 440, 489, 2607–2609). The function still tries CLI-name first; when both keys exist, it returns whichever stale run happens to live under the CLI-name directory.
+
+This surfaced during the cal-com reprint retro (#597, F2): `printing-press publish package --json` returned `run_id: 20260405-183800` (a stale April 5 run keyed under `cal-com-pp-cli`) while the actual run that just promoted was `20260504-205634` (keyed under `cal-com`). Every reprint of a CLI that has both keys hits this.
+
+---
+
+## Requirements
+
+- R1. When both `manuscripts/<api-slug>/<run>/` and `manuscripts/<cli-name>/<run>/` exist, `resolveManuscripts(cliName, apiName)` returns the API-slug path and its most-recent run ID. *(Issue F2 positive)*
+- R2. When only `manuscripts/<cli-name>/<run>/` exists, `resolveManuscripts` falls back to the CLI-name path. *(Issue F2 legacy fallback)*
+- R3. When only `manuscripts/<api-slug>/<run>/` exists, `resolveManuscripts` returns the API-slug path. *(Issue F2 negative — API-slug only)*
+- R4. The fuzzy resolve fallback (`resolveManuscriptDir`) still fires when neither keyed directory has runs. *(Preserves existing behavior)*
+- R5. `printing-press publish package --dir <library>/<api-slug> --json` returns a `run_id` that matches the staged CLI's `.printing-press.json` `run_id` for the cal-com scenario (and any reprint where both keys exist). *(Issue F2 regression)*
+- R6. The comments on the lookup branches (`internal/cli/publish.go:473–476` and `478–481`) accurately describe which key is the SKILL convention and which is the legacy binary convention.
+
+---
+
+## Scope Boundaries
+
+- The inline manuscripts-warn lookup inside `runValidation` (`internal/cli/publish.go:621–628`) is **not** changed in this plan. The issue's scope boundary states "Does NOT touch other manuscripts consumers. Publish-package read path only." That block is a warn-only check that mirrors the same priority order — it stays as-is and may be revisited in a follow-up if the inconsistency causes confusion.
+- No changes to the SKILL's archive convention or to `pipeline.PublishedManuscriptsRoot()`.
+- No changes to `findMostRecentRun` or `resolveManuscriptDir` themselves.
+- No changes to `phase5ProofsDir` (separate consumer of CLI-name and API-name keys for proof location; unaffected by lookup priority for runs).
+
+### Deferred to Follow-Up Work
+
+- Aligning the inline warn-only lookup at `internal/cli/publish.go:621–628` with the same API-slug-first priority. Currently out of scope per issue boundary.
+
+---
+
+## Context & Research
+
+### Relevant Code and Patterns
+
+- `internal/cli/publish.go:464` — `resolveManuscripts(cliName, apiName)`. Single call site at `internal/cli/publish.go:368` inside `newPublishPackageCmd`.
+- `internal/cli/publish.go:838` — `findMostRecentRun(msAPIDir)`: returns the lexicographically-greatest entry (timestamp-named runs sort correctly).
+- `internal/cli/publish.go` (resolveManuscriptDir, separate file) — fuzzy fallback used when neither keyed directory yields a run.
+- `internal/cli/publish_resolve_test.go:129` — `TestManuscriptLookupPriority` simulates the chain step-by-step. The `prefers CLI name over API name` subtest currently encodes the wrong-priority behavior and must be flipped.
+- `skills/printing-press/SKILL.md:440, 489, 2607–2609` — canonical statement that archives go to `$PRESS_MANUSCRIPTS/<api-slug>/<run-id>/`.
+
+### Institutional Learnings
+
+- `docs/solutions/best-practices/checkout-scoped-printing-press-output-layout-2026-03-28.md` documents the runstate / publish / archive layout contract that established API-slug as the canonical key. The binary's lookup order has lagged that contract; this plan brings it into compliance.
+
+### External References
+
+- None required. Internal contract change.
+
+---
+
+## Key Technical Decisions
+
+- **Swap order, not "most-recent-mtime across both"**: The issue notes "Optionally pick the most-recent-modified across both when both exist." The simpler swap (API-slug first, CLI-name second) is sufficient — the SKILL writes API-slug exclusively now, so the only way the CLI-name key has a fresher run is if the user is mid-migration on a single repo, which is not a supported scenario. mtime-tiebreaking adds branch complexity for no observed benefit and would obscure the convention shift.
+- **Comment refresh**: relabel the API-slug branch as "SKILL convention" and the CLI-name branch as "legacy binary convention" rather than "new" / "old", since "new/old" was the inversion bug's own framing.
+- **Test update vs. new test**: flip the existing `prefers CLI name over API name` subtest to `prefers API name over CLI name` and call `resolveManuscripts` directly (instead of stepping through `findMostRecentRun` manually). Calling the function directly makes the priority assertion authoritative rather than indirectly inferred from chain steps.
+
+---
+
+## Open Questions
+
+### Resolved During Planning
+
+- **Should the warn-only lookup at `:621–628` be updated in the same change?** No. Issue scope boundary excludes it; tracked as Deferred to Follow-Up Work.
+- **Does the current test suite need a new file?** No. `internal/cli/publish_resolve_test.go` already exists for these helpers; extend it.
+
+### Deferred to Implementation
+
+- Whether the existing `TestManuscriptLookupPriority/prefers_CLI_name_over_API_name` subtest should be deleted-and-replaced or renamed-and-rewritten. Either is fine; pick whichever produces the cleanest diff.
+
+---
+
+## Implementation Units
+
+- U1. **Swap lookup order in `resolveManuscripts` and update tests**
+
+**Goal:** Make `resolveManuscripts` consult the API-slug directory before the CLI-name directory and refresh the lookup-branch comments. Update the priority test to assert the new order and cover the cal-com regression scenario.
+
+**Requirements:** R1, R2, R3, R4, R5, R6
+
+**Dependencies:** None.
+
+**Files:**
+- Modify: `internal/cli/publish.go` (`resolveManuscripts` body and surrounding comments at `:464–485`)
+- Modify: `internal/cli/publish_resolve_test.go` (`TestManuscriptLookupPriority` subtests; add API-slug-priority assertion using `resolveManuscripts` directly)
+
+**Approach:**
+- In `resolveManuscripts`, attempt the API-slug key first (`filepath.Join(msRoot, apiName)`), then the CLI-name key (`filepath.Join(msRoot, cliName)`), then the fuzzy fallback. The fall-through pattern (`if rid, err := findMostRecentRun(...); err == nil && rid != ""` returning early) stays the same — only the order of the two named-key blocks changes.
+- Refresh the comments to label branch 1 as the SKILL archive convention (API-slug) and branch 2 as the legacy binary convention (CLI-name). Drop the `new convention` / `old convention` framing.
+- In `TestManuscriptLookupPriority`, replace the existing `prefers CLI name over API name` subtest with one that calls `resolveManuscripts("steam-web-pp-cli", "steam-web")` directly against a fixture containing both keys and asserts the API-slug path and run win. Update the fallback subtests' fixture descriptions to match the new priority.
+- Add a regression subtest mirroring the cal-com case: fixture with `manuscripts/cal-com/<recent-run>/` and `manuscripts/cal-com-pp-cli/<old-run>/`, call `resolveManuscripts("cal-com-pp-cli", "cal-com")`, assert API-slug path and recent run.
+
+**Patterns to follow:**
+- Existing `resolveManuscripts` structure (sequential keyed lookups, fuzzy fallback at the bottom) — preserve the shape; only flip branch order.
+- Existing `createRunDir` test helper at `internal/cli/publish_resolve_test.go:13` — reuse it for the new subtests.
+- Subtest naming and `assert` style already in `TestManuscriptLookupPriority`.
+
+**Test scenarios:**
+- Happy path: fixture has both `manuscripts/<api-slug>/<recent-run>/` and `manuscripts/<cli-name>/<old-run>/`. `resolveManuscripts(cliName, apiName)` returns the API-slug path and the recent run ID. *(Covers R1; the cal-com regression case from F2 positive)*
+- Edge case: fixture has only `manuscripts/<cli-name>/<run>/`. `resolveManuscripts(cliName, apiName)` returns the CLI-name path and that run. *(Covers R2)*
+- Edge case: fixture has only `manuscripts/<api-slug>/<run>/`. `resolveManuscripts(cliName, apiName)` returns the API-slug path and that run. *(Covers R3)*
+- Edge case: fixture has neither named key but has a fuzzy-matchable directory (e.g., `manuscripts/steam/` for `apiName="steam-web"`). `resolveManuscripts` returns the fuzzy match. *(Covers R4)*
+- Edge case: empty manuscripts root. `resolveManuscripts` returns empty path and empty run ID without erroring.
+- Integration scenario: end-to-end `publish package --json` against a staged CLI whose `.printing-press.json` `run_id` matches an API-slug-keyed manuscripts directory; the JSON output's `run_id` field equals the manifest's `run_id`. Verified manually against a cal-com fixture as the explicit R5 acceptance check (see Verification below). *(Covers R5)*
+
+**Verification:**
+- `go test ./internal/cli/...` passes with the new and updated subtests.
+- `go vet ./...` and `go build -o ./printing-press ./cmd/printing-press` succeed.
+- `golangci-lint run ./...` clean on the touched file.
+- `scripts/golden.sh verify` passes (no expected impact on golden fixtures — change is internal to a runtime helper, not a generator output).
+- **R5 manual acceptance check (required before commit):** with both `~/printing-press/manuscripts/cal-com/<recent-run>/` and `~/printing-press/manuscripts/cal-com-pp-cli/<old-run>/` present locally, run `printing-press publish package --dir ~/printing-press/library/cal-com --category productivity --target /tmp/pp-r5 --json` and confirm the emitted `run_id` field equals the staged `cal-com/.printing-press.json` `run_id` (which should match `<recent-run>`). If a cal-com library is not available locally, fabricate the equivalent two-key fixture under any other API slug and run the analogous command.
+
+---
+
+## System-Wide Impact
+
+- **Interaction graph:** Single in-binary call site (`newPublishPackageCmd` at `internal/cli/publish.go:368`). No external consumers of `resolveManuscripts`. The inline warn-only lookup at `:621–628` is unaffected (and intentionally not aligned per scope).
+- **Error propagation:** No change. Function still returns `("", "")` when no candidate yields a run.
+- **State lifecycle risks:** None. Read-only filesystem inspection; no migrations or stashing.
+- **API surface parity:** No CLI flag or output schema change. JSON output continues to use the existing `run_id` / `manuscripts_included` fields; only the *value* of `run_id` becomes correct in the both-keys-present case.
+- **Integration coverage:** End-to-end `publish package --json` covered by R5. Unit-level priority chain covered by `TestManuscriptLookupPriority`.
+- **Unchanged invariants:** The fuzzy fallback (`resolveManuscriptDir`) behavior and the `findMostRecentRun` lex-sort tiebreak are preserved exactly.
+
+---
+
+## Risks & Dependencies
+
+| Risk | Mitigation |
+|------|------------|
+| A reprint of a CLI that has *only* the legacy CLI-name key but no API-slug key would behave the same after the swap (CLI-name still wins via the second branch) — but a CLI in mid-migration that has a stale API-slug dir from a prior regen and a fresh CLI-name dir from a manual workflow would now silently pick the stale API-slug run. | Document the SKILL-convention-first semantics in the refreshed comment. The mid-migration case is not a supported scenario; if observed, a separate cleanup path or mtime-tiebreak can be added in follow-up. |
+| Test fixture renames could leave a stale subtest name pointing at the wrong assertion. | Re-run the full `TestManuscriptLookupPriority` table after edits; verify subtest names and assertions match. |
+
+---
+
+## Documentation / Operational Notes
+
+- No user-facing docs require updates. SKILL.md already documents the API-slug archive convention as canonical.
+- Commit scope: `cli` (per AGENTS.md scope mapping).
+
+---
+
+## Sources & References
+
+- **Origin issue:** [#598 — WU-2: resolveManuscripts prefers API-slug keying over CLI-name](https://github.com/mvanhorn/cli-printing-press/issues/598)
+- **Parent retro:** [#597 — Cal.com (reprint) retro](https://github.com/mvanhorn/cli-printing-press/issues/597)
+- Related code: `internal/cli/publish.go:464` (`resolveManuscripts`), `internal/cli/publish_resolve_test.go:129` (`TestManuscriptLookupPriority`)
+- Related learnings: `docs/solutions/best-practices/checkout-scoped-printing-press-output-layout-2026-03-28.md`
+- SKILL convention: `skills/printing-press/SKILL.md:440, 489, 2607–2609`
diff --git a/internal/cli/publish.go b/internal/cli/publish.go
index a44ff106..7fc3229f 100644
--- a/internal/cli/publish.go
+++ b/internal/cli/publish.go
@@ -462,7 +462,8 @@ func removeStashedDirs(dirs []stashedDir) {
}
// resolveManuscripts finds the manuscripts directory and most recent run ID
-// for a CLI. Tries CLI name first (new convention), then API name, then fuzzy.
+// for a CLI. Tries API name first (SKILL convention), then CLI name (legacy
+// binary convention), then fuzzy resolve.
func resolveManuscripts(cliName, apiName string) (msDir string, runID string) {
if apiName == "" {
apiName = naming.TrimCLISuffix(cliName)
@@ -470,16 +471,16 @@ func resolveManuscripts(cliName, apiName string) (msDir string, runID string) {
msRoot := pipeline.PublishedManuscriptsRoot()
- // 1. Try CLI name (new convention: manuscripts/<cli-name>/<run>/)
- cliMsDir := filepath.Join(msRoot, cliName)
- if rid, err := findMostRecentRun(cliMsDir); err == nil && rid != "" {
- return cliMsDir, rid
- }
- // 2. Try API name (old convention: manuscripts/<api-name>/<run>/)
+ // 1. Try API name (SKILL convention: manuscripts/<api-slug>/<run>/)
apiMsDir := filepath.Join(msRoot, apiName)
if rid, err := findMostRecentRun(apiMsDir); err == nil && rid != "" {
return apiMsDir, rid
}
+ // 2. Try CLI name (legacy binary convention: manuscripts/<cli-name>/<run>/)
+ cliMsDir := filepath.Join(msRoot, cliName)
+ if rid, err := findMostRecentRun(cliMsDir); err == nil && rid != "" {
+ return cliMsDir, rid
+ }
// 3. Fuzzy resolve (strip suffixes, prefix match)
return resolveManuscriptDir(msRoot, apiName)
}
diff --git a/internal/cli/publish_resolve_test.go b/internal/cli/publish_resolve_test.go
index f58c7ed5..302fb068 100644
--- a/internal/cli/publish_resolve_test.go
+++ b/internal/cli/publish_resolve_test.go
@@ -5,6 +5,7 @@ import (
"path/filepath"
"testing"
+ "github.com/mvanhorn/cli-printing-press/v3/internal/pipeline"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -126,73 +127,92 @@ func TestResolveManuscriptDir(t *testing.T) {
})
}
-func TestManuscriptLookupPriority(t *testing.T) {
- // Simulates the full lookup chain: CLI name → API name → fuzzy resolve
- // This is what the publish package command does.
+// withManuscriptsRoot wires a temp dir as PRINTING_PRESS_HOME and returns the
+// manuscripts/ path, giving tests deterministic control over what
+// resolveManuscripts sees on disk.
+func withManuscriptsRoot(t *testing.T) string {
+ t.Helper()
+ t.Setenv("PRINTING_PRESS_HOME", t.TempDir())
+ msRoot := pipeline.PublishedManuscriptsRoot()
+ require.NoError(t, os.MkdirAll(msRoot, 0o755))
+ return msRoot
+}
- t.Run("prefers CLI name over API name", func(t *testing.T) {
- msRoot := t.TempDir()
- createRunDir(t, msRoot, "steam-web-pp-cli", "run-cli")
- createRunDir(t, msRoot, "steam-web", "run-api")
- createRunDir(t, msRoot, "steam", "run-slug")
+func TestManuscriptLookupPriority(t *testing.T) {
+ // Exercises resolveManuscripts directly: API-slug (SKILL convention)
+ // wins over CLI-name (legacy binary convention); fuzzy is the last resort.
- cliName := "steam-web-pp-cli"
+ t.Run("prefers API name over CLI name when both exist", func(t *testing.T) {
+ msRoot := withManuscriptsRoot(t)
+ createRunDir(t, msRoot, "steam-web", "run-api-recent")
+ createRunDir(t, msRoot, "steam-web-pp-cli", "run-cli-old")
- // Step 1: CLI name
- cliDir := filepath.Join(msRoot, cliName)
- runID, err := findMostRecentRun(cliDir)
- assert.NoError(t, err)
- assert.Equal(t, "run-cli", runID) // CLI name wins
+ dir, runID := resolveManuscripts("steam-web-pp-cli", "steam-web")
+ assert.Equal(t, filepath.Join(msRoot, "steam-web"), dir)
+ assert.Equal(t, "run-api-recent", runID)
})
- t.Run("falls back to API name when CLI name missing", func(t *testing.T) {
- msRoot := t.TempDir()
- // No CLI name directory
- createRunDir(t, msRoot, "steam-web", "run-api")
- createRunDir(t, msRoot, "steam", "run-slug")
+ t.Run("falls back to CLI name when API name dir missing (legacy fallback)", func(t *testing.T) {
+ msRoot := withManuscriptsRoot(t)
+ createRunDir(t, msRoot, "steam-web-pp-cli", "run-cli")
- cliName := "steam-web-pp-cli"
+ dir, runID := resolveManuscripts("steam-web-pp-cli", "steam-web")
+ assert.Equal(t, filepath.Join(msRoot, "steam-web-pp-cli"), dir)
+ assert.Equal(t, "run-cli", runID)
+ })
- // Step 1: CLI name — fails
- cliDir := filepath.Join(msRoot, cliName)
- cliRunID, _ := findMostRecentRun(cliDir)
- assert.Empty(t, cliRunID)
+ t.Run("returns API name dir when only API name exists", func(t *testing.T) {
+ msRoot := withManuscriptsRoot(t)
+ createRunDir(t, msRoot, "steam-web", "run-api")
- // Step 2: API name
- apiDir := filepath.Join(msRoot, "steam-web")
- apiRunID, err := findMostRecentRun(apiDir)
- assert.NoError(t, err)
- assert.Equal(t, "run-api", apiRunID) // API name is second priority
+ dir, runID := resolveManuscripts("steam-web-pp-cli", "steam-web")
+ assert.Equal(t, filepath.Join(msRoot, "steam-web"), dir)
+ assert.Equal(t, "run-api", runID)
})
- t.Run("falls back to fuzzy when both CLI and API names missing", func(t *testing.T) {
- msRoot := t.TempDir()
+ t.Run("falls back to fuzzy when neither named key has runs", func(t *testing.T) {
+ msRoot := withManuscriptsRoot(t)
createRunDir(t, msRoot, "steam", "run-slug")
- apiName := "steam-web"
-
- // Steps 1+2 fail, step 3: fuzzy resolve
- dir, runID := resolveManuscriptDir(msRoot, apiName)
+ dir, runID := resolveManuscripts("steam-web-pp-cli", "steam-web")
assert.Equal(t, filepath.Join(msRoot, "steam"), dir)
assert.Equal(t, "run-slug", runID)
})
t.Run("returns empty when nothing matches", func(t *testing.T) {
- msRoot := t.TempDir()
+ msRoot := withManuscriptsRoot(t)
createRunDir(t, msRoot, "notion", "run-notion")
- cliName := "steam-web-pp-cli"
- apiName := "steam-web"
-
- cliDir := filepath.Join(msRoot, cliName)
- runID, _ := findMostRecentRun(cliDir)
+ dir, runID := resolveManuscripts("steam-web-pp-cli", "steam-web")
+ assert.Empty(t, dir)
assert.Empty(t, runID)
+ })
- apiDir := filepath.Join(msRoot, apiName)
- runID, _ = findMostRecentRun(apiDir)
- assert.Empty(t, runID)
+ t.Run("regression: cal-com prefers API-slug recent run over stale CLI-name run", func(t *testing.T) {
+ // Pre-fix, resolveManuscripts returned the stale CLI-name run instead.
+ msRoot := withManuscriptsRoot(t)
+ createRunDir(t, msRoot, "cal-com", "20260504-205634")
+ createRunDir(t, msRoot, "cal-com-pp-cli", "20260405-183800")
- _, runID = resolveManuscriptDir(msRoot, apiName)
+ dir, runID := resolveManuscripts("cal-com-pp-cli", "cal-com")
+ assert.Equal(t, filepath.Join(msRoot, "cal-com"), dir)
+ assert.Equal(t, "20260504-205634", runID)
+ })
+
+ t.Run("empty apiName falls back to TrimCLISuffix(cliName)", func(t *testing.T) {
+ msRoot := withManuscriptsRoot(t)
+ createRunDir(t, msRoot, "steam-web", "run-derived")
+
+ dir, runID := resolveManuscripts("steam-web-pp-cli", "")
+ assert.Equal(t, filepath.Join(msRoot, "steam-web"), dir)
+ assert.Equal(t, "run-derived", runID)
+ })
+
+ t.Run("empty manuscripts root returns empty without erroring", func(t *testing.T) {
+ _ = withManuscriptsRoot(t)
+
+ dir, runID := resolveManuscripts("steam-web-pp-cli", "steam-web")
+ assert.Empty(t, dir)
assert.Empty(t, runID)
})
}
← 24e7e60f fix(cli): default live dogfood happy_path on mutators to --d
·
back to Cli Printing Press
·
fix(cli): emit invalidateCache() in every printed client.go 9c5b882a →