Skip to content

feat: ship initial Spotify CLI vertical slice - #9

Merged
rianjs merged 7 commits into
mainfrom
feat/initial-spotify-cli
Jul 22, 2026
Merged

rianjs merged 7 commits into
mainfrom
feat/initial-spotify-cli

Conversation

@rianjs

@rianjs rianjs commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Build the initial secure, cross-platform Spotify CLI vertical slice on one long-lived branch. The exact-head dedicated-account smoke, fleet-aligned release prerequisites, independent review approval, and CI all pass.

Delivery

  • Package/repository name: spotify-cli
  • Executable and release archive name: sptfy
  • One logical commit per issue, reviewed at each ticket boundary
  • Final squash merge to main
  • Closing keywords are added only after each issue boundary is complete

Progress

Validation

  • Exact-head local and CI verification at 76735a3
  • make check, including the fake live-smoke sequencing, opt-in guard, backend pinning, and cleanup harness
  • Opt-in live harness with an isolated eight-variable environment and encrypted-file credential backend
  • Build-tagged refresh helper that expires the access token without printing credential material
  • Production and no-1Password credential-tag test suites
  • Static Linux credential smoke with CGO_ENABLED=0
  • GitHub CI: Linux/macOS/Windows CGO-split builds; coverage, security, tidy, lint, and PR-title gates
  • Required identity-check manifest-drift gate
  • GoReleaser check and six-target snapshot with Homebrew, Winget, Chocolatey, deb, and rpm render inspection
  • Shared macOS Mach-O, Security.framework, and hermetic Keychain probes
  • Shared auto-release path/commit gates (v0.1.1 for the first run) and exact release-config preflight
  • Standard workflow_dispatch dry-runs on both auto-release and release callers
  • Track search exact-stream, projection, breadcrumb, paging-token, retry, cancellation, and secret-redaction tests
  • Command-level continuation-offset assertion, eight-variable/backend hermeticity assertions, and ordinary tagged-helper compilation
  • Dedicated-account PKCE live smoke at 76735a3: identity, normal/no-result/paginated search, projections, credential replacement, forced refresh, clear, re-init, and complete hermetic cleanup
  • Sol accepts the final release and dependency-inversion design; final exact-head convergence is recorded after the live rerun
  • Terra TDD review findings addressed; monit-reviewer approved the exact head
  • All nine exact-head GitHub checks pass, including the macOS release-build/package-render gate
  • git diff --check

Release readiness

  • Release signing is self-signing; Apple notarization is not part of this release.
  • Winget and Chocolatey indexing is asynchronous after their release submissions are accepted.
  • Auto-release and release use the same eight secret mappings as the deployed Go CLI fleet, including TAP_GITHUB_TOKEN for both tag creation and Homebrew publishing; recent successful shared-workflow releases prove those organization inputs are operational.
  • GitHub cannot dispatch this new repository's release workflow until the caller first exists on the default branch (the pre-merge dispatch returns 404); the pinned gate and preflight have been run locally without publishing.

Closes #2
Closes #3
Closes #4
Closes #5
Closes #6
Closes #7
Closes #8
Closes #1

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from d1954d6 to 59f46d5 Compare July 22, 2026 11:46

rianjs commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Coverage review

Independent GPT-5.6 Terra TDD review for issue #2.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch 2 times, most recently from 341b209 to 7cc7d04 Compare July 22, 2026 11:52

rianjs commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

TDD feedback resolution for issue #2:

  • The draft PR body now closes only completed ticket boundaries, so feat: add secure configuration and credential storage #3–test: verify the initial Spotify CLI vertical slice #8 are no longer presented as delivered.
  • The suggested Markdown substring test was implemented for evaluation, then removed after architect review: it coupled go test to prose formatting, created a synthetic root package, and still could not validate the semantic command contract. Runtime behavior in later tickets will receive executable tests instead.
  • Current verification: GOCACHE=/tmp/sptfy-go-cache go test ./... and git diff --check pass.

@rianjs-bot rianjs-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: 7cc7d04d311c
Profile: codex-rianjs-bot - Posting as: rianjs-bot[bot]

Summary

Reviewer Findings
documentation:docs 2
policies:conventions 0
documentation:docs (2 findings)

Major - spotify-cli-behavior.md:37

init is specified as a complete PKCE setup flow but never defines the redirect URI strategy or tells users to allowlist the CLI callback URI in their Spotify application. Spotify requires the authorization and token-exchange redirect URI to exactly match an allowlisted URI (and disallows localhost); without this contract, a user with only a client ID cannot complete the documented flow and implementers cannot safely choose the callback listener. Specify the loopback callback URI/port behavior (or a user-supplied redirect-URI flag) and require the matching 127.0.0.1 URI to be registered in the Spotify dashboard.

Minor - spotify-cli-behavior.md:1

This is the new durable behavior contract, but neither docs/development.md—the source of truth named by both agent entrypoints—nor the README links to it. As a result, maintainers and agents following the documented entrypoint will miss the command, security, and release decisions. Add a concise link from docs/development.md (and, if appropriate, the README) identifying this file as the Spotify-specific behavior specification and its planned-release scope.

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
documentation:docs complete_broad docs/development.md, spotify-cli-behavior.md unavailable Review was limited to the two assigned documentation changes; the optional cli-common sibling checkout was not present, so its shared contracts could not be inspected locally.
policies:conventions complete_broad docs/development.md, spotify-cli-behavior.md unavailable Shared cli-common and .github convenience copies were not present in the review workspace, so this review is limited to repository-visible guidance and the assigned diff.

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 1m 17s | unavailable | gpt-5.6-terra | cr 0.10.267
Field Value
Model gpt-5.6-terra
Reviewers documentation:docs, policies:conventions
Engine codex_cli · gpt-5.6-terra
Reviewed by cr · rianjs-bot[bot]
Duration 1m 17s wall · 1m 25s compute
Cost unavailable
Tokens 362.0k in / 5.2k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 16.0k 187 11.0k unavailable unavailable 5s
documentation:docs gpt-5.6-terra 228.2k 3.1k 193.0k unavailable unavailable 51s
policies:conventions gpt-5.6-terra 82.9k 1.6k 67.6k unavailable unavailable 23s
orchestrator-rollup gpt-5.6-terra 34.9k 319 26.6k unavailable unavailable 4s

Comment thread spotify-cli-behavior.md Resolved
Comment thread spotify-cli-behavior.md Resolved
@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 7cc7d04 to 6cfd470 Compare July 22, 2026 12:17

@rianjs-bot rianjs-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: 6cfd4709de63
Profile: codex-rianjs-bot - Posting as: rianjs-bot[bot]

Summary

Reviewer Findings
documentation:docs 0
policies:conventions 0

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
documentation:docs complete_broad docs/development.md, spotify-cli-behavior.md unavailable Review limited to the two assigned documentation changes; external Spotify API behavior was cross-checked against current official documentation.
policies:conventions complete_broad docs/development.md, spotify-cli-behavior.md unavailable The referenced shared cli-common and .github convenience copies are not present locally, so this review is limited to repo-local guidance and the changed documentation.

2 PR discussion threads considered. 2 summarized; 2 resolved.


Completed in 1m 39s | unavailable | gpt-5.6-terra | cr 0.10.267
Field Value
Model gpt-5.6-terra
Reviewers documentation:docs, policies:conventions
Engine codex_cli · gpt-5.6-terra
Reviewed by cr · rianjs-bot[bot]
Duration 1m 39s wall · 1m 08s compute
Cost unavailable
Tokens 416.7k in / 3.8k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 57.8k 456 45.3k unavailable unavailable 5s
documentation:docs gpt-5.6-terra 210.6k 2.1k 176.9k unavailable unavailable 44s
policies:conventions gpt-5.6-terra 65.0k 797 50.9k unavailable unavailable 15s
orchestrator-rollup gpt-5.6-terra 83.3k 497 68.1k unavailable unavailable 3s

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch 6 times, most recently from 3a203e6 to 06b8c8f Compare July 22, 2026 13:50

@rianjs-bot rianjs-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: 06b8c8f6e027
Profile: codex-rianjs-bot - Posting as: rianjs-bot[bot]

Summary

Reviewer Findings
go:implementation-tests 0
policies:conventions 0
structure:repo-health 0
automation:ci-release 1
documentation:docs 1
automation:ci-release (1 finding)

Major - Makefile:2

make check now compiles, tests, and lints with keyring_nopassage, but the required CI build/test jobs invoke the shared Go actions without this build tag. The merge gate therefore validates a different source set from the documented local gate, so regressions in the tagged configuration can merge unnoticed. Pass this tag to the CI build/test/lint actions (or make CI invoke the Make targets) so both gates use the same build configuration.

documentation:docs (1 finding)

Minor - spotify-cli-behavior.md:208

“Configuration output … never values” contradicts the documented config show and config path behavior: both intentionally emit non-secret values such as the client ID, redirect URI, credential reference, and resolved paths. Clarify this as “never credential contents/secret values” so the acceptance suite does not direct future tests to reject the intended output.

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
go:implementation-tests incomplete_skipped cmd/sptfy/main.go, cmd/sptfy/main_test.go, go.mod, internal/cmd/configcmd/config.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/config/config_test.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/exitcode/exitcode.go, internal/exitcode/exitcode_test.go, internal/token/envelope.go, internal/token/envelope_test.go go.sum Full CGO-enabled test run is blocked by the workspace path containing spaces, which clang mishandles for its module-cache path; CGO_ENABLED=0 go test ./..., go vet ./..., and git diff --check pass.
policies:conventions complete_broad cmd/sptfy/main.go, docs/development.md, internal/cmd/configcmd/config.go, internal/cmd/root/root.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, spotify-cli-behavior.md unavailable Shared cli-common and .github documentation convenience copies were not present locally; review relied on the repository-local development guide and behavioral specification.
structure:repo-health incomplete_skipped cmd/sptfy/main.go, go.mod, internal/cmd/configcmd/config.go, internal/cmd/root/root.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, internal/token/envelope.go go.sum Review limited to the assigned architecture/configuration files. go test ./... passed with CGO_ENABLED=0; the normal CGO build is blocked by this sandbox's malformed clang module-cache path.
automation:ci-release complete_broad Makefile, go.mod, go.sum unavailable Local test execution is constrained by sandboxed macOS CGO/Clang cache permissions.; Review limited to assigned Makefile and Go module metadata; CI workflow was inspected only to assess Make/merge-gate alignment.
documentation:docs complete_broad docs/development.md, spotify-cli-behavior.md unavailable Narrow documentation review; command/configuration implementation was inspected for contract alignment. go test ./... could not build in this workspace because the compiler received a path with spaces.

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 1m 54s | unavailable | gpt-5.6-terra | cr 0.10.267
Field Value
Model gpt-5.6-terra
Reviewers go:implementation-tests, policies:conventions, structure:repo-health, automation:ci-release, documentation:docs
Engine codex_cli · gpt-5.6-terra
Reviewed by cr · rianjs-bot[bot]
Duration 1m 54s wall · 5m 46s compute
Cost unavailable
Tokens 1.6M in / 18.3k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 112.7k 1.0k 79.1k unavailable unavailable 15s
go:implementation-tests gpt-5.6-terra 467.7k 4.2k 415.5k unavailable unavailable 1m 21s
policies:conventions gpt-5.6-terra 129.8k 2.2k 98.6k unavailable unavailable 40s
structure:repo-health gpt-5.6-terra 359.4k 3.3k 307.5k unavailable unavailable 1m 08s
automation:ci-release gpt-5.6-terra 167.4k 2.9k 138.8k unavailable unavailable 1m 04s
documentation:docs gpt-5.6-terra 239.8k 3.6k 198.9k unavailable unavailable 1m 12s
orchestrator-rollup gpt-5.6-terra 145.6k 1.1k 108.0k unavailable unavailable 5s

Comment thread Makefile Resolved
Comment thread spotify-cli-behavior.md Resolved
@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch 2 times, most recently from 6e2cb53 to 7d502ad Compare July 22, 2026 15:50

@rianjs-bot rianjs-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: 7d502adfd7e1
Profile: codex-rianjs-bot - Posting as: rianjs-bot[bot]

Summary

Reviewer Findings
automation:ci-release 0
go:implementation-tests 0
policies:conventions 0
structure:repo-health 0
documentation:docs 0

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
automation:ci-release complete_broad .github/workflows/ci.yml, Makefile, go.mod, go.sum unavailable Review limited to the assigned CI, Makefile, and module metadata changes. Local tagged Go build/test execution was blocked by the sandbox's malformed clang module-cache path; workflow and target configuration were inspected statically.
go:implementation-tests complete_broad cmd/sptfy/main.go, cmd/sptfy/main_test.go, go.mod, go.sum, internal/cmd/configcmd/config.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/config/config_test.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/exitcode/exitcode.go, internal/exitcode/exitcode_test.go, internal/token/envelope.go, internal/token/envelope_test.go unavailable Full tests passed with CGO_ENABLED=0 and keyring_nopassage; the default CGO build is blocked by this sandbox's space-containing compiler-cache path.
policies:conventions complete_broad .github/workflows/ci.yml, Makefile, cmd/sptfy/main.go, docs/development.md, internal/cmd/configcmd/config.go, internal/cmd/root/root.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, spotify-cli-behavior.md unavailable Review was limited to convention drift visible in the assigned changed files.; The canonical cli-common and shared .github documentation convenience copies were not present locally; review used the repository's visible development guide and behavior contract.
structure:repo-health complete_broad Makefile, cmd/sptfy/main.go, go.mod, go.sum, internal/cmd/configcmd/config.go, internal/cmd/root/root.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, internal/token/envelope.go unavailable Review limited to assigned changed files and repository-local guidance. The tagged test suite passed with CGO_ENABLED=0; default CGO compilation was blocked by the sandbox workspace path being split by clang.
documentation:docs complete_broad docs/development.md, spotify-cli-behavior.md unavailable Reviewed the assigned documentation against the current repository source and command definitions; the behavior document explicitly describes a planned initial-release contract, not all currently implemented commands.

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 2m 03s | unavailable | gpt-5.6-terra | cr 0.10.267
Field Value
Model gpt-5.6-terra
Reviewers automation:ci-release, go:implementation-tests, policies:conventions, structure:repo-health, documentation:docs
Engine codex_cli · gpt-5.6-terra
Reviewed by cr · rianjs-bot[bot]
Duration 2m 03s wall · 5m 58s compute
Cost unavailable
Tokens 2.3M in / 20.7k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 183.0k 1.7k 119.0k unavailable unavailable 12s
automation:ci-release gpt-5.6-terra 213.5k 3.3k 181.5k unavailable unavailable 1m 06s
go:implementation-tests gpt-5.6-terra 579.0k 4.3k 516.9k unavailable unavailable 1m 30s
policies:conventions gpt-5.6-terra 231.9k 2.9k 193.8k unavailable unavailable 57s
structure:repo-health gpt-5.6-terra 720.0k 4.6k 648.7k unavailable unavailable 1m 34s
documentation:docs gpt-5.6-terra 130.9k 2.1k 103.2k unavailable unavailable 32s
orchestrator-rollup gpt-5.6-terra 224.2k 1.7k 156.2k unavailable unavailable 3s

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 7d502ad to 4129158 Compare July 22, 2026 15:57
@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 15d64a4 to 05f4c6a Compare July 22, 2026 16:46
@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 05f4c6a to ebbc095 Compare July 22, 2026 16:55
@rianjs

rianjs commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Test coverage review

No blocking coverage gaps found in the Issue #4 delta. Tests cover PKCE S256/exact redirect reuse, callback state/denial/timeout paths, stdin authorization, token refresh and persistence, identity rendering/JSON, failure classification, rollback, and secret redaction. The composed root test also exercises init → verification → me.

Validated with go test -tags=keyring_nopassage ./... and git diff --check.

@rianjs

rianjs commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Coverage review

  • Major — 1Password opt-out behavior is not proven. test-no1password only reruns the existing suite with build tags. Existing tests use file/memory backends or mocked stores; none selects an op* backend through ProductionOpener. It would pass if the opt-out tag were ignored or disabled backends silently fell back. Add a small opt-out-tagged test asserting an op, op-connect, or op-desktop selection fails with credstore.ErrBackendNotImplemented.

The CGO matrix, static Linux test run, tidy diff check, and configured gofmt/goimports lint gate otherwise cover the stated CI intent.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 7ae1cd7 to ae3bb7e Compare July 22, 2026 17:22
@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch 2 times, most recently from 32b608e to 235571b Compare July 22, 2026 18:34
@rianjs

rianjs commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Test coverage findings

  • Major — internal/client/client_test.go:124: Retry tests cover only terminal failure. Add a transient-then-200 case (at least 429 and one 5xx) asserting the decoded page, exact waits, and no extra attempt. Current tests would pass if retries always ended in ErrUpstream, so successful recovery is unproven.

  • Minor — internal/cmd/searchcmd/search_test.go:17: Search has no command-level API-failure coverage. Add 401/403 and terminal upstream cases that assert Config vs Upstream exit classification and that a response-body canary is absent from the returned error. mecmd covers this separately; the new searchcmd.classify can regress unnoticed.

  • Nit — internal/cmd/searchcmd/search_test.go:59: Include search track q --json in pre-session validation to lock the resource-command “never JSON” contract.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 235571b to 1de5ead Compare July 22, 2026 18:37
@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 1de5ead to 9b33314 Compare July 22, 2026 18:40
@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch 6 times, most recently from 613cb99 to 55f1f2c Compare July 22, 2026 21:34
@rianjs
rianjs marked this pull request as ready for review July 22, 2026 21:38

@monit-reviewer monit-reviewer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: 55f1f2c7c445
Profile: codex-monit-reviewer - Posting as: monit-reviewer

Summary

Reviewer Findings
go:implementation-tests 0
architecture:solid-reviewer-agnostic 1
automation:ci-release 0
policies:conventions 0
structure:harness-engineering 0
architecture:solid-reviewer-agnostic (1 finding)

Major - internal/cmd/initcmd/init.go:135

U-S2: The Cobra handler owns the security-critical initialization use case: opening the store, enforcing overwrite policy, authorizing and verifying, persisting the credential and configuration, and rolling the credential back on failure. This couples transaction semantics to CLI presentation and forces any additional entry point to reproduce or invoke Cobra-specific code. Extract an internal initialization service with an Initialize(ctx, Setup, Options) operation and injected config/store/auth/verifier collaborators; leave RunE to translate flags and prompts, call the service, classify its errors, and render the result.

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
go:implementation-tests incomplete_skipped cmd/sptfy/main.go, cmd/sptfy/main_test.go, go.mod, internal/auth/authorizer.go, internal/auth/authorizer_test.go, internal/auth/token_source.go, internal/auth/token_source_test.go, internal/client/client.go, internal/client/client_test.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/mecmd/me.go, internal/cmd/mecmd/me_test.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/searchcmd/search.go, internal/cmd/searchcmd/search_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/config/config_test.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/credentials/no1password_test.go, internal/exitcode/exitcode.go, internal/exitcode/exitcode_test.go, internal/output/me.go, internal/output/me_test.go, internal/output/track.go, internal/output/track_test.go, internal/session/session.go, internal/session/session_test.go, internal/token/envelope.go, internal/token/envelope_test.go go.sum, internal/livesmoke/doc.go, internal/livesmoke/expire_test.go Focused Go implementation and behavioral-test review only. Full test execution is blocked by the sandbox disallowing loopback listeners; packages relying on httptest cannot run here.
architecture:solid-reviewer-agnostic complete_broad cmd/sptfy/main.go, go.mod, internal/auth/authorizer.go, internal/auth/token_source.go, internal/client/client.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/mecmd/me.go, internal/cmd/root/root.go, internal/cmd/searchcmd/search.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, internal/exitcode/exitcode.go, internal/output/me.go, internal/output/track.go, internal/session/session.go, internal/token/envelope.go, spotify-cli-behavior.md unavailable Review was limited to the assigned changed files, with adjacent tests and repository guidance consulted for context.; make check could not complete because the sandbox denied golangci-lint cache writes and CGO compilation under the workspace path; tagged tests were also limited by denied loopback listeners. These environment failures were not treated as diff-caused findings.
automation:ci-release complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, go.mod, go.sum, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/live-smoke-test.sh, scripts/live-smoke.sh unavailable Automation-only review. GoReleaser configuration and workflow syntax validated successfully. Full snapshot and live-helper compilation could not complete because the sandboxed macOS environment cannot access its clang module cache or bind localhost.
policies:conventions incomplete_skipped .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, README.md, cmd/sptfy/main.go, docs/development.md, go.mod, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/mecmd/me.go, internal/cmd/root/root.go, internal/cmd/searchcmd/search.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/live-smoke-test.sh, scripts/live-smoke.sh, spotify-cli-behavior.md go.sum Review limited to repo-local convention-facing changes. The referenced cli-common and shared .github convenience copies were not present, so no claims were made about undocumented upstream requirements.; go.sum was intentionally not inspected because it is generated dependency-checksum data with no convention-facing content.
structure:harness-engineering complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, README.md, cmd/sptfy/main.go, docs/development.md, go.mod, go.sum, internal/auth/authorizer.go, internal/auth/token_source.go, internal/client/client.go, internal/config/config.go, internal/credentials/credentials.go, internal/session/session.go, internal/token/envelope.go, packaging/identity.yml, scripts/live-smoke-test.sh, scripts/live-smoke.sh, spotify-cli-behavior.md unavailable Review intentionally focused on structural, automation, and durable-boundary risks. GoReleaser configuration validation passed. Full Go test targets could not run in this sandbox because its compiler cache path contains spaces that break clang and loopback listener creation is disallowed.

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 4m 36s | unavailable | gpt-5.6-terra, gpt-5.6-sol | cr 0.10.267
Field Value
Model gpt-5.6-terra, gpt-5.6-sol
Reviewers go:implementation-tests, architecture:solid-reviewer-agnostic, automation:ci-release, policies:conventions, structure:harness-engineering
Engine codex_cli · gpt-5.6-terra, gpt-5.6-sol
Reviewed by cr · monit-reviewer
Duration 4m 36s wall · 9m 43s compute
Cost unavailable
Tokens 2.9M in / 32.2k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 54.1k 2.4k 32.3k unavailable unavailable 51s
go:implementation-tests gpt-5.6-terra 788.1k 6.1k 700.2k unavailable unavailable 1m 52s
architecture:solid-reviewer-agnostic gpt-5.6-sol 931.7k 9.9k 856.8k unavailable unavailable 3m 28s
automation:ci-release gpt-5.6-terra 173.7k 3.3k 145.9k unavailable unavailable 1m 06s
policies:conventions gpt-5.6-terra 265.4k 3.7k 220.7k unavailable unavailable 55s
structure:harness-engineering gpt-5.6-terra 640.5k 4.3k 553.5k unavailable unavailable 1m 24s
orchestrator-rollup gpt-5.6-terra 92.3k 2.5k 64.3k unavailable unavailable 5s

Comment thread internal/cmd/initcmd/init.go Outdated
return exitcode.New(exitcode.Usage, err)
}

store, err := dependencies.OpenStore(credentials.OpenRequest{

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

U-S2: The Cobra handler owns the security-critical initialization use case: opening the store, enforcing overwrite policy, authorizing and verifying, persisting the credential and configuration, and rolling the credential back on failure. This couples transaction semantics to CLI presentation and forces any additional entry point to reproduce or invoke Cobra-specific code. Extract an internal initialization service with an Initialize(ctx, Setup, Options) operation and injected config/store/auth/verifier collaborators; leave RunE to translate flags and prompts, call the service, classify its errors, and render the result.

Reply inline to this comment.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 55f1f2c to 498f2fc Compare July 22, 2026 21:58

@monit-reviewer monit-reviewer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: 498f2fc2e84f
Profile: codex-monit-reviewer - Posting as: monit-reviewer

Summary

Reviewer Findings
architecture:solid-reviewer-agnostic 1
go:implementation-tests 0
automation:ci-release 0
policies:conventions 0
structure:harness-engineering 1
architecture:solid-reviewer-agnostic (1 finding)

Minor - internal/credentials/credentials.go:36

U-I1: Store is a package-owned union of every credential-store capability, so consumers depend on operations they never use. For example, the session test double must implement Backend, Delete, and Exists even though session only needs Get, Set, and Close; this will make future store changes ripple through unrelated commands and doubles. Define narrow consumer-owned store/opener contracts near init, session, and config command code, adapting the production opener at the root composition boundary, or split this interface into composable capability interfaces.

structure:harness-engineering (1 finding)

Major - .github/workflows/ci.yml:12

The release configuration is not exercised by CI: this workflow builds and tests the Go code, but never runs goreleaser check or a snapshot/render validation for .goreleaser.yml and the package manifests. A later change can therefore pass every required PR check yet fail only after the tag-triggered release workflow begins. Add a release-validation job that installs the pinned GoReleaser version and runs at least goreleaser check plus a non-publishing snapshot/render check, with assertions for the expected archive/package outputs.

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
architecture:solid-reviewer-agnostic complete_broad internal/auth/authorizer.go, internal/auth/token_source.go, internal/client/client.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/root/root.go, internal/config/config.go, internal/credentials/credentials.go, internal/session/session.go, internal/token/envelope.go unavailable Canonical cli-common shared documentation was absent from the checkout and could not be retrieved; local development guidance and spotify-cli-behavior.md were used.; Review was limited to the 11 assigned changed files plus directly relevant tests and repository guidance.; With CGO disabled, 69 tests passed; 5 listener-dependent tests could not run because the sandbox prohibits loopback sockets. Focused init/config/credentials/session/token tests all passed.
go:implementation-tests incomplete_skipped cmd/sptfy/main.go, cmd/sptfy/main_test.go, internal/auth/authorizer.go, internal/auth/authorizer_test.go, internal/auth/token_source.go, internal/auth/token_source_test.go, internal/client/client.go, internal/client/client_test.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/mecmd/me_test.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/searchcmd/search.go, internal/cmd/searchcmd/search_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/config/config_test.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/credentials/no1password_test.go, internal/exitcode/exitcode_test.go, internal/livesmoke/expire_test.go, internal/output/me_test.go, internal/output/track.go, internal/output/track_test.go, internal/session/session.go, internal/session/session_test.go, internal/token/envelope.go, internal/token/envelope_test.go go.mod, go.sum, internal/exitcode/exitcode.go, internal/livesmoke/doc.go, internal/output/me.go Review limited to Go implementation quality and behavioral-test adequacy. Full go test ./... could not run because the sandbox disallows IPv6 loopback and the environment's CGO compiler cannot resolve this workspace path; a focused client retry test passed.
automation:ci-release complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, go.mod, go.sum, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/live-smoke-test.sh, scripts/live-smoke.sh unavailable Runtime test execution is constrained by the sandbox: local HTTP listeners are denied and the Xcode/CGO module-cache path is unavailable. Static shell validation and GoReleaser configuration validation completed.
policies:conventions complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, README.md, cmd/sptfy/main.go, docs/development.md, go.mod, go.sum, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/root/root.go, internal/cmd/searchcmd/search.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/live-smoke-test.sh, scripts/live-smoke.sh, spotify-cli-behavior.md unavailable The canonical cli-common and shared .github documentation checkouts referenced by docs/development.md were not present locally; review was limited to concrete drift visible in the assigned changes and repository-local contract.; make check reached lint but the local macOS CGO type-check failed while importing cli-common's Keychain dependency in this sandbox; no worktree changes resulted.
structure:harness-engineering incomplete_skipped .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, README.md, cmd/sptfy/main.go, docs/development.md, internal/auth/authorizer.go, internal/auth/token_source.go, internal/client/client.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/config/config.go, internal/credentials/credentials.go, internal/session/session.go, internal/token/envelope.go, packaging/identity.yml, scripts/live-smoke-test.sh, scripts/live-smoke.sh, spotify-cli-behavior.md go.mod, go.sum Review limited to the assigned changed files and repository-local development guidance. Full Go test execution was attempted but is constrained by this sandbox: CGO compilation cannot resolve the workspace path and httptest cannot bind an IPv6 loopback listener.

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 3m 37s | unavailable | gpt-5.6-sol, gpt-5.6-terra | cr 0.10.267
Field Value
Model gpt-5.6-sol, gpt-5.6-terra
Reviewers architecture:solid-reviewer-agnostic, go:implementation-tests, automation:ci-release, policies:conventions, structure:harness-engineering
Engine codex_cli · gpt-5.6-sol, gpt-5.6-terra
Reviewed by cr · monit-reviewer
Duration 3m 37s wall · 8m 27s compute
Cost unavailable
Tokens 2.9M in / 28.9k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 140.7k 3.6k 101.9k unavailable unavailable 23s
architecture:solid-reviewer-agnostic gpt-5.6-sol 982.5k 7.6k 905.7k unavailable unavailable 2m 45s
go:implementation-tests gpt-5.6-terra 410.7k 3.6k 348.4k unavailable unavailable 1m 16s
automation:ci-release gpt-5.6-terra 310.3k 3.5k 269.3k unavailable unavailable 1m 32s
policies:conventions gpt-5.6-terra 434.4k 3.1k 371.5k unavailable unavailable 1m 10s
structure:harness-engineering gpt-5.6-terra 387.3k 3.7k 334.1k unavailable unavailable 1m 13s
orchestrator-rollup gpt-5.6-terra 194.8k 3.8k 149.8k unavailable unavailable 6s

Comment thread .github/workflows/ci.yml
@@ -12,14 +12,26 @@ concurrency:
permissions:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File-level note: .github/workflows/ci.yml

The release configuration is not exercised by CI: this workflow builds and tests the Go code, but never runs goreleaser check or a snapshot/render validation for .goreleaser.yml and the package manifests. A later change can therefore pass every required PR check yet fail only after the tag-triggered release workflow begins. Add a release-validation job that installs the pinned GoReleaser version and runs at least goreleaser check plus a non-publishing snapshot/render check, with assertions for the expected archive/package outputs.

Reply inline to this comment.

Comment thread internal/credentials/credentials.go Outdated
}

// Store is the effect boundary command tests replace.
type Store interface {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

U-I1: Store is a package-owned union of every credential-store capability, so consumers depend on operations they never use. For example, the session test double must implement Backend, Delete, and Exists even though session only needs Get, Set, and Close; this will make future store changes ripple through unrelated commands and doubles. Define narrow consumer-owned store/opener contracts near init, session, and config command code, adapting the production opener at the root composition boundary, or split this interface into composable capability interfaces.

Reply inline to this comment.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 498f2fc to e85e5d4 Compare July 22, 2026 22:07

@monit-reviewer monit-reviewer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: e85e5d4f9afa
Profile: codex-monit-reviewer - Posting as: monit-reviewer

Summary

Reviewer Findings
automation:ci-release 1
architecture:solid-reviewer-agnostic 0
go:implementation-tests 0
policies:conventions 0
structure:harness-engineering 1
automation:ci-release (1 finding)

Minor - .github/workflows/release-build-check.yml:34

~> v2 resolves to whatever the latest GoReleaser v2 release is when a PR runs, so this new pre-merge release gate is not deterministic and its artifact/render behavior can change without a repository diff. Pin version to the exact vetted v2 release (and update it deliberately) to keep release validation reproducible.

structure:harness-engineering (1 finding)

Major - internal/credentials/credentials.go:36

The shared Store/Opener contract still requires every root-level test double and consumer path to implement Backend, Get, Set, Delete, and Exists, even though each command needs only a subset. The newly added command-local narrow interfaces are reached only by adapting this broad producer-owned interface in root, so future credential operations will continue to expand a cross-command fake and composition boundary. Make root accept consumer-specific openers (or adapt the concrete production opener at composition time) and remove the broad credentials.Store/Opener contract; each command can then own and enforce only its required capability.

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
automation:ci-release incomplete_skipped .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, go.mod, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/live-smoke-test.sh, scripts/live-smoke.sh, scripts/verify-package-render.sh go.sum The local GoReleaser snapshot could not complete because the sandbox blocks required Go module-cache writes, local test listeners, and the cgo toolchain cache; goreleaser check and shell syntax checks passed.
architecture:solid-reviewer-agnostic complete_broad internal/auth/authorizer.go, internal/auth/token_source.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/root/root.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/session/session.go, internal/session/session_test.go, internal/token/envelope.go unavailable Tests could not run in the restricted sandbox.
go:implementation-tests incomplete_skipped cmd/sptfy/main.go, cmd/sptfy/main_test.go, internal/auth/authorizer.go, internal/auth/authorizer_test.go, internal/auth/token_source.go, internal/auth/token_source_test.go, internal/client/client.go, internal/client/client_test.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/mecmd/me_test.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/searchcmd/search.go, internal/cmd/searchcmd/search_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/config/config_test.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/credentials/no1password_test.go, internal/exitcode/exitcode.go, internal/exitcode/exitcode_test.go, internal/output/me.go, internal/output/me_test.go, internal/output/track.go, internal/output/track_test.go, internal/session/session.go, internal/session/session_test.go, internal/token/envelope.go, internal/token/envelope_test.go go.mod, go.sum, internal/livesmoke/doc.go, internal/livesmoke/expire_test.go go test ./... could not complete in the sandbox: network listener creation is restricted and CGO compilation fails on the workspace path.
policies:conventions complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, README.md, cmd/sptfy/main.go, docs/development.md, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/root/root.go, internal/cmd/searchcmd/search.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/live-smoke-test.sh, scripts/live-smoke.sh, scripts/verify-package-render.sh, spotify-cli-behavior.md unavailable The canonical cli-common and shared .github documentation was not available locally, and remote source pages could not be retrieved; review is limited to repository-local guidance and the visible diff.
structure:harness-engineering complete_broad .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .goreleaser.yml, Makefile, cmd/sptfy/main.go, docs/development.md, go.mod, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/cmd/root/root.go, internal/config/config.go, internal/credentials/credentials.go, internal/session/session.go, scripts/verify-package-render.sh, spotify-cli-behavior.md unavailable Review limited to assigned files and their directly relevant composition/tests. Local make check/make test could not complete because the sandbox blocks loopback listeners and the host CGO toolchain cache path is invalid.

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 8m 34s | unavailable | gpt-5.6-terra, gpt-5.6-sol | cr 0.10.267
Field Value
Model gpt-5.6-terra, gpt-5.6-sol
Reviewers automation:ci-release, architecture:solid-reviewer-agnostic, go:implementation-tests, policies:conventions, structure:harness-engineering
Engine codex_cli · gpt-5.6-terra, gpt-5.6-sol
Reviewed by cr · monit-reviewer
Duration 8m 34s wall · 13m 39s compute
Cost unavailable
Tokens 2.7M in / 34.7k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 259.5k 4.9k 203.8k unavailable unavailable 24s
automation:ci-release gpt-5.6-terra 399.8k 4.8k 355.3k unavailable unavailable 1m 55s
architecture:solid-reviewer-agnostic gpt-5.6-sol 601.5k 7.1k 542.5k unavailable unavailable 7m 26s
go:implementation-tests gpt-5.6-terra 382.2k 4.4k 313.6k unavailable unavailable 1m 13s
policies:conventions gpt-5.6-terra 443.7k 3.8k 383.5k unavailable unavailable 1m 06s
structure:harness-engineering gpt-5.6-terra 284.4k 4.5k 239.6k unavailable unavailable 1m 26s
orchestrator-rollup gpt-5.6-terra 329.6k 5.2k 268.0k unavailable unavailable 7s

- name: Install GoReleaser
uses: goreleaser/goreleaser-action@v6
with:
version: "~> v2"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

~> v2 resolves to whatever the latest GoReleaser v2 release is when a PR runs, so this new pre-merge release gate is not deterministic and its artifact/render behavior can change without a repository diff. Pin version to the exact vetted v2 release (and update it deliberately) to keep release validation reproducible.

Reply inline to this comment.

Comment thread internal/credentials/credentials.go Outdated
}

// Store is the effect boundary command tests replace.
type Store interface {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The shared Store/Opener contract still requires every root-level test double and consumer path to implement Backend, Get, Set, Delete, and Exists, even though each command needs only a subset. The newly added command-local narrow interfaces are reached only by adapting this broad producer-owned interface in root, so future credential operations will continue to expand a cross-command fake and composition boundary. Make root accept consumer-specific openers (or adapt the concrete production opener at composition time) and remove the broad credentials.Store/Opener contract; each command can then own and enforce only its required capability.

Reply inline to this comment.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from e85e5d4 to 7c6ee8d Compare July 22, 2026 22:18

@monit-reviewer monit-reviewer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: 7c6ee8d6e64e
Profile: codex-monit-reviewer - Posting as: monit-reviewer

Summary

Reviewer Findings
architecture:solid-reviewer-agnostic 0
go:implementation-tests 0
automation:ci-release 0
policies:conventions 1
structure:harness-engineering 1
policies:conventions (1 finding)

Minor - .github/workflows/release.yml:31

This trailing blank line makes git diff --check fail. Remove it, and remove the same end-of-file blank-line violations reported in .goreleaser.yml and the packaging manifests/scripts so the documented diff-check gate remains clean.

structure:harness-engineering (1 finding)

Major - .github/workflows/release-build-check.yml:5

The path-filtered release gate omits .github/workflows/auto-release.yml, even though that newly added caller controls the release trigger and tag-token mapping. A PR that changes only that workflow can merge without the advertised pre-merge release validation, allowing a broken release handoff to reach main. Add auto-release.yml (and any other release caller/configuration inputs) to this gate's paths, or make the release validation unfiltered and required.

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
architecture:solid-reviewer-agnostic complete_broad cmd/sptfy/main.go, cmd/sptfy/main_test.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/session/session.go, internal/session/session_test.go unavailable unavailable
go:implementation-tests complete_broad cmd/sptfy/main.go, cmd/sptfy/main_test.go, internal/auth/authorizer.go, internal/auth/authorizer_test.go, internal/auth/token_source.go, internal/auth/token_source_test.go, internal/client/client.go, internal/client/client_test.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/mecmd/me_test.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/searchcmd/search.go, internal/cmd/searchcmd/search_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/config/config_test.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/credentials/no1password_test.go, internal/session/session.go, internal/session/session_test.go, internal/token/envelope.go, internal/token/envelope_test.go unavailable unavailable
automation:ci-release incomplete_skipped .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, go.mod, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/live-smoke-test.sh, scripts/live-smoke.sh, scripts/verify-package-render.sh go.sum The local sandbox prevented completing make snapshot because it disallows test listeners and its cgo cache path is unusable; GoReleaser configuration validation completed successfully.
policies:conventions complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, README.md, cmd/sptfy/main.go, docs/development.md, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/root/root.go, internal/cmd/searchcmd/search.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/verify-package-render.sh, spotify-cli-behavior.md unavailable The optional local cli-common and shared .github standards copies were not present, so this review relied on repository-local guidance and visible workflow/configuration conventions.
structure:harness-engineering complete_broad .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .goreleaser.yml, Makefile, cmd/sptfy/main.go, docs/development.md, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/cmd/root/root.go, internal/config/config.go, internal/credentials/credentials.go, internal/session/session.go, scripts/verify-package-render.sh, spotify-cli-behavior.md unavailable Review focused on assigned structural, credential-composition, and release-validation surfaces. Network-listening tests could not run in this sandbox; CGO-disabled tests passed except tests requiring loopback listeners.
unassigned incomplete_unassigned unavailable internal/exitcode/exitcode.go, internal/exitcode/exitcode_test.go, internal/livesmoke/doc.go, internal/livesmoke/expire_test.go, internal/output/me.go, internal/output/me_test.go, internal/output/track.go, internal/output/track_test.go changed files were not assigned to a selected reviewer

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 4m 54s | unavailable | gpt-5.6-sol, gpt-5.6-terra | cr 0.10.267
Field Value
Model gpt-5.6-sol, gpt-5.6-terra
Reviewers architecture:solid-reviewer-agnostic, go:implementation-tests, automation:ci-release, policies:conventions, structure:harness-engineering
Engine codex_cli · gpt-5.6-sol, gpt-5.6-terra
Reviewed by cr · monit-reviewer
Duration 4m 54s wall · 9m 49s compute
Cost unavailable
Tokens 2.2M in / 26.7k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 409.8k 6.2k 337.9k unavailable unavailable 22s
architecture:solid-reviewer-agnostic gpt-5.6-sol 21.5k 985 10.0k unavailable unavailable 3m 59s
go:implementation-tests gpt-5.6-terra 327.3k 2.6k 272.9k unavailable unavailable 2m 12s
automation:ci-release gpt-5.6-terra 333.8k 3.9k 290.6k unavailable unavailable 1m 07s
policies:conventions gpt-5.6-terra 189.4k 2.8k 147.5k unavailable unavailable 41s
structure:harness-engineering gpt-5.6-terra 317.2k 3.6k 271.4k unavailable unavailable 1m 12s
orchestrator-rollup gpt-5.6-terra 583.7k 6.6k 502.3k unavailable unavailable 13s


on:
pull_request:
paths:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path-filtered release gate omits .github/workflows/auto-release.yml, even though that newly added caller controls the release trigger and tag-token mapping. A PR that changes only that workflow can merge without the advertised pre-merge release validation, allowing a broken release handoff to reach main. Add auto-release.yml (and any other release caller/configuration inputs) to this gate's paths, or make the release validation unfiltered and required.

Reply inline to this comment.

Comment thread .github/workflows/release.yml Outdated
macos-cert-password: ${{ secrets.MACOS_CERT_PASSWORD }}
macos-cert-cn: ${{ secrets.MACOS_CERT_CN }}
macos-cert-leaf-sha: ${{ secrets.MACOS_CERT_LEAF_SHA }}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This trailing blank line makes git diff --check fail. Remove it, and remove the same end-of-file blank-line violations reported in .goreleaser.yml and the packaging manifests/scripts so the documented diff-check gate remains clean.

Reply inline to this comment.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from 7c6ee8d to a3db6f7 Compare July 22, 2026 22:25

@monit-reviewer monit-reviewer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR Review

Reviewed commit: a3db6f7d7f20
Profile: codex-monit-reviewer - Posting as: monit-reviewer

Summary

Reviewer Findings
automation:ci-release 2
architecture:solid-reviewer-agnostic 1
go:implementation-tests 0
policies:conventions 0
structure:harness-engineering 0
automation:ci-release (2 findings)

Major - .github/workflows/release-build-check.yml:5

The path-filtered release gate omits version.txt, even though packaging/identity.yml declares it as the release version source. A version-only PR can therefore change the tag/package version consumed by the shared release automation while skipping the GoReleaser snapshot and package-render verification. Add version.txt to this filter (or remove the filter) so version-source changes receive the release validation.

Major - .github/workflows/auto-release.yml:18

Both release callers reference the shared publishing workflows through the mutable @v1 tag (this line and .github/workflows/release.yml:21). Moving that tag can alter tag creation or publishing behavior without any reviewed change in this repository, defeating the stated pinned shared-workflow release gate. Pin each uses: reference to the vetted immutable shared release revision/version (the release-readiness contract identifies v0.1.1 for this initial release), and update it deliberately.

architecture:solid-reviewer-agnostic (1 finding)

Major - internal/session/session.go:24

[U-I1] OpenFunc forces every authenticated command to depend on the provider-owned concrete *Session, which in turn exposes the concrete client.Client through a public field. The current me and search track consumers need different, much smaller capabilities, but their tests must assemble real session/client HTTP machinery; future authenticated commands will copy this coupling. Define consumer-owned session/opener interfaces near each command (for example Close/Scopes/Me for me and Close/SearchTracks for search), then adapt Opener.Open at the root composition boundary while keeping token and credential lifecycle inside this package.

Reviewer Coverage

Reviewer Status Inspected Skipped Constraints
automation:ci-release complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/verify-package-render.sh unavailable GoReleaser configuration validation passed. A full snapshot build could not complete in this sandbox because dependency/network access and host compiler caches are restricted.; Review scope was limited to assigned CI, release, Make, and packaging files. The shared automation repository was not present locally.
architecture:solid-reviewer-agnostic complete_broad internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/config/config.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/session/session.go, internal/session/session_test.go unavailable Review scope was limited to the ten assigned changed files, with composition context inspected in cmd/sptfy/main.go and authenticated command consumers.; Verification was environment-constrained: make check and make test could not complete because the sandbox broke CGO/clang module-cache paths and prohibited httptest listener binding; git diff --check passed.
go:implementation-tests complete_broad cmd/sptfy/main.go, cmd/sptfy/main_test.go, go.mod, go.sum, internal/auth/authorizer.go, internal/auth/authorizer_test.go, internal/auth/token_source.go, internal/auth/token_source_test.go, internal/client/client.go, internal/client/client_test.go, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/init_test.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/mecmd/me_test.go, internal/cmd/root/root.go, internal/cmd/root/root_test.go, internal/cmd/searchcmd/search.go, internal/cmd/searchcmd/search_test.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/config/config_test.go, internal/credentials/credentials.go, internal/credentials/credentials_test.go, internal/credentials/no1password_test.go, internal/exitcode/exitcode.go, internal/exitcode/exitcode_test.go, internal/livesmoke/doc.go, internal/livesmoke/expire_test.go, internal/output/me.go, internal/output/me_test.go, internal/output/track.go, internal/output/track_test.go, internal/session/session.go, internal/session/session_test.go, internal/token/envelope.go, internal/token/envelope_test.go unavailable Full test execution is constrained by the sandbox, which disallows loopback listeners used by httptest; non-listener packages passed with CGO disabled.
policies:conventions complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, README.md, cmd/sptfy/main.go, docs/development.md, internal/cmd/configcmd/config.go, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/cmd/mecmd/me.go, internal/cmd/root/root.go, internal/cmd/searchcmd/search.go, internal/cmd/setcredential/setcredential.go, internal/config/config.go, internal/credentials/credentials.go, packaging/chocolatey/spotify-cli.nuspec, packaging/chocolatey/tools/chocolateyInstall.ps1, packaging/identity.yml, packaging/winget/OpenCLICollective.spotify-cli.installer.yaml, packaging/winget/OpenCLICollective.spotify-cli.locale.en-US.yaml, packaging/winget/OpenCLICollective.spotify-cli.yaml, scripts/verify-package-render.sh, spotify-cli-behavior.md unavailable The canonical cli-common and shared .github convention documents were not available as local convenience copies, so this review did not infer requirements beyond the repository-visible guidance.; make check reached lint but could not complete because the local macOS environment failed CGO preprocessing while importing the keychain dependency; this did not identify a repository convention issue.
structure:harness-engineering complete_broad .github/workflows/auto-release.yml, .github/workflows/ci.yml, .github/workflows/release-build-check.yml, .github/workflows/release.yml, .goreleaser.yml, Makefile, cmd/sptfy/main.go, docs/development.md, internal/cmd/initcmd/init.go, internal/cmd/initcmd/initializer.go, internal/cmd/root/root.go, internal/config/config.go, internal/credentials/credentials.go, internal/session/session.go, scripts/verify-package-render.sh, spotify-cli-behavior.md unavailable Did not perform live release publishing, secret validation, or external workflow execution.; Review focused on structural/release-validation and composition-boundary risks. Targeted Go tests could not compile in this workspace because the local path contains spaces and the CGO toolchain treated it as an invalid compiler argument.
unassigned incomplete_unassigned unavailable scripts/live-smoke-test.sh, scripts/live-smoke.sh changed files were not assigned to a selected reviewer

0 PR discussion threads considered. 0 summarized; 0 resolved.


Completed in 3m 39s | unavailable | gpt-5.6-terra, gpt-5.6-sol | cr 0.10.267
Field Value
Model gpt-5.6-terra, gpt-5.6-sol
Reviewers automation:ci-release, architecture:solid-reviewer-agnostic, go:implementation-tests, policies:conventions, structure:harness-engineering
Engine codex_cli · gpt-5.6-terra, gpt-5.6-sol
Reviewed by cr · monit-reviewer
Duration 3m 39s wall · 8m 45s compute
Cost unavailable
Tokens 4.5M in / 40.5k out

Per-workstream usage

Workstream Model In Out Cache read Cache create Cost Duration
orchestrator-selection gpt-5.6-terra 795.0k 8.7k 690.2k unavailable unavailable 46s
automation:ci-release gpt-5.6-terra 446.9k 4.1k 406.8k unavailable unavailable 1m 33s
architecture:solid-reviewer-agnostic gpt-5.6-sol 1.1M 6.6k 994.8k unavailable unavailable 2m 15s
go:implementation-tests gpt-5.6-terra 587.7k 4.7k 503.3k unavailable unavailable 1m 27s
policies:conventions gpt-5.6-terra 379.4k 3.6k 327.7k unavailable unavailable 1m 16s
structure:harness-engineering gpt-5.6-terra 323.3k 3.8k 279.3k unavailable unavailable 1m 18s
orchestrator-rollup gpt-5.6-terra 912.9k 8.9k 801.0k unavailable unavailable 7s


on:
pull_request:
paths:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path-filtered release gate omits version.txt, even though packaging/identity.yml declares it as the release version source. A version-only PR can therefore change the tag/package version consumed by the shared release automation while skipping the GoReleaser snapshot and package-render verification. Add version.txt to this filter (or remove the filter) so version-source changes receive the release validation.

Reply inline to this comment.


jobs:
auto-release:
uses: open-cli-collective/.github/.github/workflows/auto-release.yml@v1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both release callers reference the shared publishing workflows through the mutable @v1 tag (this line and .github/workflows/release.yml:21). Moving that tag can alter tag creation or publishing behavior without any reviewed change in this repository, defeating the stated pinned shared-workflow release gate. Pin each uses: reference to the vetted immutable shared release revision/version (the release-readiness contract identifies v0.1.1 for this initial release), and update it deliberately.

Reply inline to this comment.

Comment thread internal/session/session.go Outdated
)

// OpenFunc opens an authenticated session for a command invocation.
type OpenFunc func(context.Context, string, bool) (*Session, error)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[U-I1] OpenFunc forces every authenticated command to depend on the provider-owned concrete *Session, which in turn exposes the concrete client.Client through a public field. The current me and search track consumers need different, much smaller capabilities, but their tests must assemble real session/client HTTP machinery; future authenticated commands will copy this coupling. Define consumer-owned session/opener interfaces near each command (for example Close/Scopes/Me for me and Close/SearchTracks for search), then adapt Opener.Open at the root composition boundary while keeping token and credential lifecycle inside this package.

Reply inline to this comment.

@rianjs
rianjs force-pushed the feat/initial-spotify-cli branch from a3db6f7 to 76735a3 Compare July 22, 2026 22:31
@rianjs

rianjs commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Approval override request for the current head (76735a3). Please approve after confirming the addressed findings.

All actionable review findings are resolved, including the initialization service boundary, consumer-owned credential and authenticated-session capabilities, deterministic GoReleaser pin, package-render gate, and complete release-validation path inputs.

The one declined suggestion is pinning the two shared reusable workflows to immutable revisions. This repository intentionally retains open-cli-collective/.github/...@v1: matching the adjacent Go CLI fleet and following the centrally maintained rolling v1 workflow contract is an explicit project requirement. GoReleaser itself remains exactly pinned to v2.17.0 in the PR gate.

Local evidence on this head's content: make check, ShellCheck, actionlint, goreleaser check, and the non-publishing six-platform make snapshot with package-render assertions all pass.

@monit-reviewer monit-reviewer left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving after an explicit PR author override request following a prior codereview pass.

@rianjs
rianjs merged commit 80d1116 into main Jul 22, 2026
9 checks passed
@rianjs
rianjs deleted the feat/initial-spotify-cli branch July 22, 2026 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants