Archive milestone artifacts: - milestones/v1.0-ROADMAP.md (full roadmap archive) - milestones/v1.0-REQUIREMENTS.md (26/26 requirements complete) - milestones/v1.0-phases/ (8 phase directories with plans, summaries, verifications) Updated: - PROJECT.md: full evolution review, all consolidation requirements validated - ROADMAP.md: collapsed to milestone summary with archive link - STATE.md: reset for next milestone - MILESTONES.md: created with stats and accomplishments - RETROSPECTIVE.md: created with lessons learned Deleted: - REQUIREMENTS.md (archived, fresh for next milestone) 8 phases, 17 plans, 34 tasks, 84 tests added, 6 days
7.4 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-backend-correctness | 01 | execute | 1 |
|
true |
|
|
Purpose: Remove global mutable state (startupErr), prevent world-writable config files, and ensure MPRIS failures are observable in logs.
Output: Modified backend/app.go and backend/config/config.go with all three fixes applied.
<execution_context> @/home/caleb/.config/opencode/get-shit-done/workflows/execute-plan.md @/home/caleb/.config/opencode/get-shit-done/templates/summary.md </execution_context>
@.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/02-backend-correctness/02-CONTEXT.md @.planning/phases/02-backend-correctness/02-RESEARCH.md@backend/app.go @backend/config/config.go
From backend/app.go:
// YellowJacketApp is the main application struct for Wails.
type YellowJacketApp struct {
FEBindings []any
FrontendUtil *frontendutil.FrontendUtil
logger *slog.Logger
assetHandler *assets.Handler
database *database.DB
library *library.Library
player *player.Player
playlist *playlist.Service
queue *queue.Queue
mediaControls mediacontrols.Handler
appContext context.Context
appConfig *config.Config
}
var startupErr error // line 134 — TO BE REMOVED
func (yj *YellowJacketApp) OnStartup(ctx context.Context) // line 137 — uses startupErr
func (yj *YellowJacketApp) OnDomReady(ctx context.Context) // line 251 — checks startupErr
MPRIS callback closures at lines 181-203:
OnPause: func() { _ = yj.player.Pause() },
OnPlayPause: func() {
if yj.player.IsPlaying() {
_ = yj.player.Pause()
} else {
yj.queue.Play()
}
},
OnStop: func() { _ = yj.player.Pause() },
OnSeek: func(positionSec int) {
_ = yj.player.Seek(positionSec)
},
CORR-06 — Config permissions (backend/config/config.go):
- At line 152, change
os.FileMode(int(0o666))to0o644 - This is a single expression replacement — the
os.WriteFilecall signature stays the same cd /mnt/vault/dev/golang/yellowjacket && go vet ./backend/... && grep -q "startupErr error" backend/app.go && ! grep -q "^var startupErr" backend/app.go && grep -q "0o644" backend/config/config.go && ! grep -q "0o666" backend/config/config.go Package-level startupErr is gone; YellowJacketApp has startupErr field; OnStartup and OnDomReady reference yj.startupErr; config.go writes with 0o644 permissions
Replace the four MPRIS closures (lines 183-195) that discard errors with closures that log on failure. Use Warn level per research recommendation — these are non-fatal conditions. Keep inline closures (no named method extraction).
- OnPause (line 183): Replace
func() { _ = yj.player.Pause() }with:
func() {
if err := yj.player.Pause(); err != nil {
yj.logger.Warn("MPRIS Pause failed", "err", err)
}
}
- OnPlayPause (lines 184-189): Replace the
_ = yj.player.Pause()inside theif yj.player.IsPlaying()branch:
func() {
if yj.player.IsPlaying() {
if err := yj.player.Pause(); err != nil {
yj.logger.Warn("MPRIS PlayPause(pause) failed", "err", err)
}
} else {
yj.queue.Play()
}
}
- OnStop (line 191): Replace
func() { _ = yj.player.Pause() }with:
func() {
if err := yj.player.Pause(); err != nil {
yj.logger.Warn("MPRIS Stop failed", "err", err)
}
}
- OnSeek (lines 194-196): Replace
func(positionSec int) { _ = yj.player.Seek(positionSec) }with:
func(positionSec int) {
if err := yj.player.Seek(positionSec); err != nil {
yj.logger.Warn("MPRIS Seek failed", "err", err)
}
}
Ensure all four closures no longer use _ = to discard errors.
cd /mnt/vault/dev/golang/yellowjacket && go vet ./backend/... && ! grep -q '_ = yj.player.Pause()' backend/app.go && ! grep -q '_ = yj.player.Seek' backend/app.go && grep -c 'MPRIS.*failed' backend/app.go | grep -q '^4$'
All four MPRIS callbacks (OnPause, OnPlayPause, OnStop, OnSeek) check errors and log at Warn level; no discarded errors remain in MPRIS closures
No package-level startupErr
! grep -q "^var startupErr" backend/app.go
Struct field exists
grep -q "startupErr error" backend/app.go
Config permissions fixed
grep -q "0o644" backend/config/config.go ! grep -q "0o666" backend/config/config.go
MPRIS errors logged (4 occurrences)
test "$(grep -c 'MPRIS.*failed' backend/app.go)" -eq 4
No discarded player errors in MPRIS closures
! grep -q '_ = yj.player' backend/app.go
Linting passes
golangci-lint run ./backend/...
</verification>
<success_criteria>
- `go vet ./backend/...` passes
- `golangci-lint run ./backend/...` passes
- Package-level `startupErr` variable eliminated
- Config file written with 0o644 permissions
- All four MPRIS callbacks log errors at Warn level
</success_criteria>
<output>
After completion, create `.planning/phases/02-backend-correctness/02-01-SUMMARY.md`
</output>