Commit Graph
10 Commits
Author SHA1 Message Date
Quick 6535203791 ci: gate Go lint on the lines a branch changes
AGENTS.md told contributors CI ran the same checks as `make lint`, and the Go
job ran only gofmt and vet. A change failing the documented Go lint gate
passed all three jobs.

Running the linter as-is is not an option: the tree has ~296 findings today,
which is why this half of `make lint` was never enforced. Blocking every PR
on a cleanup nobody has scheduled gets the gate deleted again, so CI runs
with --new-from-merge-base and only the lines a branch touches have to be
clean. The count can then only fall.

golangci-lint is built from source at a pinned version rather than
downloaded. A released binary refuses to run against a Go newer than the one
it was built with, and go.mod here tracks Go closely enough that the current
release already fails that way on 1.26.4.

.golangci.yml declared version 2 while still using v1's issues.exclude-rules
key. Current golangci-lint ignores it, so the "allow repeated strings and
unchecked cleanup errors in tests" exclusions silently did not apply — 16
findings in test files that the config says to skip. Moved to
linters.exclusions, which `golangci-lint config verify` accepts.

The four lines this surfaced in scantrigger are fixed rather than excluded:
its repeated status codes and messages are now named constants, so one
condition cannot end up worded two ways.

Also drops the workflow token to contents:read and stops persisting
credentials in the three checkouts, neither of which any job needs.

Reported by CodeRabbit and Codex review on #479.
2026-07-27 00:32:15 +00:00
QuickandClaude Opus 5 e1e16020f6 ci: give the new workflow the deps it actually needs
The first run exposed two gaps in the workflow itself. go build ./... fails
without libvips headers, because h2non/bimg binds libvips through cgo and
pkg-config; the Dockerfile installs the same package. And pnpm/action-setup
resolves its version from package.json, but there is no package.json at the
repo root — the packageManager field lives in web/package.json, and a job's
defaults.run.working-directory does not apply to an action's inputs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 15:24:33 +00:00
QuickandClaude Opus 5 d8faf83c6e fix(settings): make the settings contract enforceable and fix the appearance cache
The contract manifest landed as a document nothing checked. This makes it a
mechanism, and fixes the one defect in the change set that hurt users on merge
rather than at cutover.

Web appearance cache. useTheme cleared the cache for any account whose stamp
did not match and never repopulated it — the only writers were the four
user-action setters — so every upgrading user lost their warm start on every
load, not once, and x-large-text and high-contrast users lost theirs too. The
owner-stamp protocol is replaced with per-account key namespacing
(`silo-theme:7`): a foreign value is absent rather than present-and-distrusted,
so nothing has to be deleted, the first account keeps its warm start, and there
is no shared stamp for a second tab, a stale debounce timer, or an out-of-order
effect to race on. Widening ownership to profile scope, which this manifest
requires, is now a change to appearanceCacheOwner alone. Adds the API-to-cache
mirror useTheme was missing, cancels pending debounced writes across an account
change, and re-seeds provider state during render so no frame paints the
previous account's look.

Canonicalization. writeCanonical used json.Marshal, which HTML-escapes < > and
&, and canonicalNumber used Go's 'g' format — both diverge from RFC 8785, so
the first label containing an ampersand or bound below 1e-4 would have forked
the server's ETag from every conforming client. Output is now byte-identical to
ECMAScript String() across the edge cases, verified against node. The ETag also
covers the value schemas, which decide what the server accepts and previously
could change while the tag stood still. All four derived representations are
memoized; a conditional GET no longer costs a full parse and re-serialize.

Validation. strictUnmarshal's decoder.More() answered false for a stray ] or },
so `true]` validated as a boolean. Enum matching compared fmt.Sprintf tokens, so
the string "3" satisfied an integer member. Declared steps were never enforced.
The language pattern rejected tags both mobile platforms emit unprompted
(en_US, ca-ES-valencia, ar-EG-u-nu-latn) and never normalized case, so en-US and
en-us were two rows for one preference; NormalizeValue now canonicalizes on the
shared path.

Manifest. show_forced_subtitles defaulted false where the server column is NOT
NULL DEFAULT true, which would have turned forced subtitles off for every
profile that never touched it. preferred_quality declared 13 members where the
planner speaks 6 and collapses the rest to auto. metadata_language's allowlist
was bound to the very column it migrates from. subtitle-appearance pinned
fontFamily to three families while Apple stores any installed system font.
Registers five user-facing settings the clients already ship, and corrects three
notes that described Android behaviour that was not true.

Enforcement. The package had no non-test callers, so MustLoad never ran; it now
loads and logs at startup. The inventory test compared the manifest against a
hand-copied map and could not see the drift it named; it now iterates
settingsRegistry and checks defaults too — both verified to fail on injected
drift. Adds .github/workflows/ci.yml, the repo's first CI that runs go test,
go vet, gofmt, and the frontend suite. Known pre-existing failures are named
individually in the Makefile so everything else stays gated and the list can
only shrink.

Part of #135

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 15:24:33 +00:00
Quick104 eee63772a7 feat: add AI disclosure requirements to contributing guidelines and issue templates 2026-07-23 14:37:38 -04:00
c90e736054 ci(docker): publish multi-arch images (linux/amd64 + linux/arm64) (#437)
* ci(docker): publish multi-arch images (linux/amd64 + linux/arm64)

The Dockerfile was already arch-aware (TARGETARCH in the Jellyfin apt
repo); this adds linux/arm64 to the buildx platform list so the pushed
manifest list serves both x86 servers and arm64 hosts (Apple Silicon,
Graviton, Pi 4/5). Verified locally on the arm64 runner host: image
builds and both silo and jellyfin-ffmpeg run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(docker): move image builds to GitHub-hosted runners

Replaces the single self-hosted job with a per-arch matrix (ubuntu-latest
for amd64, ubuntu-24.04-arm for arm64) so each platform builds natively
with no emulation, pushing by digest, plus a merge job that stitches the
digests into one tagged manifest list. Layer caching moves from the
persistent local builder to type=gha per-platform scopes.

The private-SDK constraint that originally forced self-hosted no longer
applies: silo-plugin-sdk is public and resolves from proxy.golang.org.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci(docker): use normalized IMAGE_LC in merge-job metadata step

Not a functional fix — metadata-action lowercases the images input
itself (proven by run 29768620803) — but keeps all image references in
the merge job on the explicit IMAGE_LC form.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 14:56:46 -04:00
QuickandClaude Fable 5 ade3a3c5d4 docs: add GitHub Sponsors funding and restructure README for selfhosters
Add .github/FUNDING.yml to enable the Sponsor button, refocus the
README on selfhoster users with a Highlights section and a Supporting
Silo section, and move contributor-facing content (dev workflow, make
targets, migrations, tests, project structure) into DEVELOPMENT.md.

AI-use disclosure: written with Claude Code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 13:14:58 -04:00
3e77f39d24 ci(v1): auto-label [v1] proposals so fork/CLI filings reach the board (#146)
The issue form only applies labels for web-form submissions; contributors
filing via API/CLI or from a fork lack the triage/write needed to set
labels, so their proposals landed unlabeled and never auto-added to the
Silo v1 project. Add an issues:opened workflow that stamps v1-proposed on
any [v1]-titled issue via the repo GITHUB_TOKEN, regardless of filer
permission.

Also drop epic from the proposal template's auto-labels: a fresh proposal
is a candidate, not yet a tracked epic. epic-ness (better: the Epic issue
type) is applied at acceptance/lock alongside v1 + milestone.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 11:26:19 -04:00
6f9427d613 docs(process): v1 scope-lock process — proposal template, CODEOWNERS gate, agent instructions (#145)
Implements the process layer of the v1 feature-lock planner: capability
proposals arrive uniform via issue form; the lock artifact
(docs/architecture/v1-scope.md) is CODEOWNERS-gated; the shared
CLAUDE.md/AGENTS.md guidelines gain the scope gate, additive-only API
rules, and pre-push checklist for agent-driven contributions.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 18:43:23 -04:00
Silo Server Migration 8f818ac0c9 ci(docker): build image on push to main via self-hosted runner
- Trigger Docker image builds on pushes to main instead of nightly cron
- Run on self-hosted Linux runner
- Drop the `nightly` tag
2026-05-25 13:03:56 -04:00
Silo Server Migration c085b12fd1 Initial Silo migration 2026-05-22 23:26:56 -04:00