`ActiveAdmin.register WarpEngine::Pipeline` declared no `permit_params`, so every edit
handed unpermitted attributes to the model and Rails raised ForbiddenAttributesError. That
is not new: the form has been unable to save for as long as it has existed. My flash
message on `update` sat at the top of the traceback and made it look like the cause, which
it was not — and it is gone anyway, because overriding an ActiveAdmin action to say
something is a poor trade for what it can break. The move is written to the log instead.
Adding a spec that would have caught it, in the host app, because that is where the
ActiveAdmin instance lives: it signs in, PUTs the form, and checks both that the record
saves and that the software link moves off the pipeline that had it. Driven the same way
by hand against the development database first — 302, the link moved, the previous holder
left without one.
The engine's other admin resources were checked for the same omission: downloads and
releases are read-only and the file manager posts to its own routes, so pipelines was the
only one affected.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The client only ever took identity from a store repository — a slug, a name, a catalog —
and the store engine's own defaults cover everything else: the host-to-asset mapping, the
install modes, the platforms, the behaviour. So `store_repository_url` is now optional:
nullable in the schema, no presence validation, the format check only when a value is
given, and the serializer answers null rather than an empty string, because the client
branches on its absence.
Adding a store is therefore a row with two fields filled in. Given a repository the
client still reads its config.json, and that file remains the authority on how the store
behaves — the admin form and the endpoint's documentation say so.
The frontend's /stores page gains a section of its own for the graphical client on the
desktop tab: what it does, that it sets the store up itself, that it is the way in on
Windows where `curl … | sh` does not exist, and links to the releases, the repository and
the documentation — now under stores/warp-engine-client, which is where that repository
lives after the rename.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- update, files and the 6 /api catalog controllers now live in the engine on
a new WarpEngine::ApiController base (same rescue/mime behavior as host)
- engine routes serve /update, /file/*path, /api/software*, /api/builds*,
/api/image/:id, /api/download at unchanged public paths via the root mount;
host routes keep only TTG endpoints (events, members, wiki, rss, swagger)
- /update secret comes from WarpEngine.config.update_secret and an
unconfigured secret now rejects every request (previously an empty
UPDATE_SECRET env accepted empty secrets)
- apipie-rails is an engine dependency (DSL in engine controllers); dummy app
configures apipie with validation off, mirroring the host
- engine request specs: catalog controller specs moved from host plus new
/update auth contract spec
Verified: engine suite 53 green, host suite 6 green, /api/software and
/api/builds byte-identical to baselines, /update 401/400 behavior intact,
admin and TTG endpoints OK.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- all catalog services (update/software/highlighted/builds/file/file-manager/
download/image + SoftwareResponseBuilder), the SoftwareUpdater platform
services and their concerns, Blueprinter serializers (incl. TimestampFields)
and the 4 DTOs now live in the engine under WarpEngine::
- constantize dispatch strings use absolute names
(WarpEngine::SoftwareUpdater::<Platform>Service)
- container paths read from WarpEngine.config everywhere (FileService,
DownloadService, FileManagerService, ArchiveExtraction, ReleaseSerializer
path rewriting); FileManagerService base path is now lazy
- engine requires blueprinter itself; gemspec declares blueprinter + rubyzip
- engine test suite: spec/dummy app (mysql warp_engine_test, catalog-only
schema), rails_helper with engine-local factories; catalog model/service
specs and factories moved from the host
- host suite keeps TTG specs and loads catalog factories from the engine
Verified: engine suite 40 green, host suite 14 green, /api/software and
/api/builds byte-identical to baselines, admin OK.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Software, Release, ReleaseAsset, ExternalLink, PlatformLink, Image,
SoftwareImage, Download now live in the engine under WarpEngine::, on top
of WarpEngine::ApplicationRecord; table names unchanged (empty prefix)
- each model runs an ActiveSupport load hook (:warp_engine_<model>) as a
host extension point
- WarpEngine::Image reads its upload path from WarpEngine.config
- host references fully qualified (services, serializers, admin, specs);
admin registrations renamed with as: so /admin URLs and route helpers are
byte-identical; factories pinned to the namespaced classes
- Member#image now class_name: "WarpEngine::Image"
Verified: full suite green, /api/software and /api/builds byte-identical to
the phase-0 baselines, admin routes unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- FileService/DownloadService: lazy container-path resolution instead of
class-load-time realpath (boot no longer requires /softwares to exist)
- downloadCount/totalDownloads: single grouped query passed as Blueprinter
option instead of per-release association counts (fixes N+1)
- admin Images: Member coupling replaced with ImageUsage owner registry
(precursor of the WarpEngine.config.image_owners hook)
- Image: UPLOAD_PATH constant replaced with call-time upload_path accessor
- proper test environment (config/environments/test.rb, softwares_test DB,
hosts.clear) — suite previously ran against the development DB
- spec fixes: case-insensitive uniqueness matchers (MySQL ai_ci collation),
DB-cascade has_many expectations, PlatformLink::SUPPORTED_PLATFORMS
- JSON baselines of /api/software and /api/builds for post-extraction diffing
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Older-style tic80 pipelines (bombexpert, mranderson) do not upload a
docs zip; the unconditional extraction raised and aborted the whole
update, so the new binary assets never got registered. Extract and
register docs only when the zip/dir exists. Covered by new
Tic80Service specs (optional docs + binary slug pickup).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>