4d014e2f45
Reviewing the project used to mean re-stating what to look at every time. docs/REVIEW.md now holds that agenda once — nine areas, each anchored to this codebase — and both entry points point at it rather than copying it: the /review-project command in .claude/commands, and a section in CLAUDE.md so a plain-language review request lands in the same place. STANDARDS.md gains a "Config file compatibility" section. The project has applied the same rule three times (Theme, JobListView, TimeoutSeconds) without ever writing it down: a new Config field is omitempty and its zero value means the previous behavior, a meaningful zero is never backfilled on load, and an unrecognised enum value reads as the default through one shared helper. With no migration step and hand-editable files, that is what keeps older configs working. Also removes docs/PLAN-compact-job-list.md, implemented in edabc57 — everything but the version bump, which now waits for the release along with the rest of the Unreleased section. .claude/settings.local.json is ignored so the shared command can be tracked without per-developer permissions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2.6 KiB
2.6 KiB
GoSentry — Standards
Quality rules and intentional behavior for contributors. Package contracts live in ARCHITECTURE.md; test conventions in TESTS.md; what a whole-project review looks at, in REVIEW.md.
Code quality
- Follow package contracts in ARCHITECTURE.md.
- User-facing errors →
dialog.ShowErroror a History event, never a silentreturn. - Pure helpers → unit test in the same package.
- Fixes with severity ≥ medium → regression test.
- Documented intentional behavior → section below, not a backlog bug.
- UI view constructors accept
*app.Service; callapp.Open()only fromrun.go.
Config file compatibility
There is no migration step: gosentry.json and jobs.json are read as-is, are
meant to be hand-editable, and may have been written by an older version. A
change to their shape has to stay compatible on its own.
- A new
Configfield is taggedomitempty, and its zero value must mean the behavior that existed before the field was added — a file written without it keeps working unchanged.DefaultConfig()still sets the value explicitly. - A zero that carries meaning is not a missing field and must not be backfilled
on load. See
DefaultTimeoutSecondsinstorage.loadOrCreateConfigandJob.TimeoutSeconds *int, where unset and0are different answers. - An unrecognised enum value reads as the default rather than an error, through
one helper that every consumer shares (
JobListView.IsCompact,ui.themeFor), and is normalized before being written back, so the file never gains a value no reader understands. - Each of the three gets a test: the default in
storage, the normalization indomain, and a round-trip through the real config file inapp.
Intentional behavior (not bugs)
RunNowis allowed during global pause and for disabled jobs.- Sequential mode runs jobs FIFO by order in
jobs.json. - Scheduler tick is 1s — sub-second
@everyintervals are not supported. - Command timeout defaults to no timeout globally (
Config.DefaultTimeoutSeconds= 0) and is overridable per job (Job.TimeoutSeconds *int: unset = inherit the global default, 0 = no timeout, positive = seconds). Neither zero may be normalized away on load — 0 is a value, not a missing field. - History tab is session-only.
JobRuntime.Logsexists only in memory for the current process. Log files on disk feed aggregate statistics viaSeedStatsonly. See ARCHITECTURE.md.
Out of scope
Larger or blocked work is tracked in ROADMAP.md (window size persistence, History column filters, CI coverage gate).