Files
gosentry/docs/STANDARDS.md
T
mixeme 84e81371c1 docs: correct the claims that no longer match the code
Four documents asserted things the code contradicts.

ARCHITECTURE's component diagram had the UI calling the autostart Manager
directly. It does not, and must not: src/ui holds no reference to the
package at all — Settings reads svc.AutostartStatus(), like everything else
it reads. The edge is folded into the existing ui→Service one, so the
diagram no longer draws the exception to the project's own rule.

platform/desktop was described in both ARCHITECTURE and DEVELOPMENT as a
"display-scale helper". It installs the .desktop entry and icon under XDG
data home; there is no scale helper in it.

The ~250-line file guideline was written as though the jobs_view and
settings_view splits had settled it. Both files are over it again and
history_view.go has never been split, so the guideline is now stated as
the target it is, with the current state named rather than implied.

STANDARDS pointed at a "CI coverage gate" item that ROADMAP does not have,
while omitting the two it does.

README's gosentry.json sample was three keys short of what the app writes
on first run — default_timeout_seconds, theme and job_list_view — which
made the one file the user is invited to hand-edit the least accurate
thing in the document. The sample is now the real default (verified by
marshalling DefaultConfig), with the keys explained, including why a zero
timeout is written out and an unset one is not. The per-job overrides for
overlap policy and timeout were undocumented despite being in the job
dialog, and the feature list had not caught up with the timeout, the theme,
or the compact job list.

Version numbers in example output paths are now <version>, matching how the
CI section already wrote them, so they cannot go stale again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 17:27:21 +03:00

75 lines
4.3 KiB
Markdown

# GoSentry — Standards
Quality rules and intentional behavior for contributors. Package contracts live
in [ARCHITECTURE.md](ARCHITECTURE.md); test conventions in [TESTS.md](TESTS.md);
what a whole-project review looks at, in [REVIEW.md](REVIEW.md).
## Code quality
- Follow package contracts in [ARCHITECTURE.md](ARCHITECTURE.md).
- User-facing errors → `dialog.ShowError` or a History event, never a silent `return`.
- 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`; call `app.Open()` only from `run.go`.
- A size that must follow the theme is **measured at build time, not written as
a pixel constant.** `theme.Padding()` and text metrics depend on the running
app's theme, text size, and DPI, so a hand-tuned number is only correct for
the one theme it was tuned against and clips under any other. Measure the real
widget, or derive the value from the theme, in a named helper: `rowOverlap`
(theme padding), `captionColumnWidth` and `textColumnWidth` (the widest of the
actual strings), `activityRowsHeight` (the list's own row template). The same
applies to a ratio computed from an absolute width — see `initialSplitOffset`.
A raw pixel literal is left only where nothing about it tracks the theme, and
says so in a comment.
## 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 `Config` field is tagged `omitempty`, 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 `DefaultTimeoutSeconds` in `storage.loadOrCreateConfig` and
`Job.TimeoutSeconds *int`, where unset and `0` are 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.
- A renamed key keeps the old field on `Config` (tagged `omitempty`) purely so
it can still be read. `storage.loadOrCreateConfig` converts it to the new
field and clears it, so the retired key disappears on the next save. See
`Config.JobsDir``Config.JobsFile`. Where the new field has a non-empty
default, clear that default before unmarshalling, or "the file omits it" and
"the file sets it" become indistinguishable and the conversion never runs.
- Each of the three gets a test: the default in `storage`, the normalization in
`domain`, and a round-trip through the real config file in `app`.
## Intentional behavior (not bugs)
- `RunNow` is allowed during global pause and for disabled jobs.
- Selecting a jobs file that already exists **loads** it: its jobs replace the
in-memory list, which is the only way the user can switch between job lists. A
path with no file behind it receives the current jobs (rename/relocate). The
switch is refused while a job is running, because adoption drops every runtime
and a finishing run would then write its result onto whichever job inherited
its ID.
- Sequential mode runs jobs FIFO by order in `jobs.json`.
- Scheduler tick is 1s — sub-second `@every` intervals 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.Logs` exists only in memory for the
current process. Log files on disk feed aggregate statistics via `SeedStats`
only. See [ARCHITECTURE.md](ARCHITECTURE.md).
## Out of scope
Larger or blocked work is tracked in [ROADMAP.md](ROADMAP.md) (update check from
GitHub releases, cron-table import/export, window size persistence, History
column filters).