upload's four real background tasks (system cleanup, stats rebuild, storage
migration, image warmup) plus the admin and user stubs registered handlers
typed as func(ctx, *asynq.Task) error. Only the asynq worker accepts that
shape; the Redis-free in-process worker's invokeHandler rejects it with
'unsupported handler type', so none of those tasks could ever run in that
deployment mode. Take payload bytes instead, which both drivers support.
Adds architecture gate check 7 forbidding asynq imports from business and
infrastructure plugins. It deliberately does not cover robfig/cron: the admin
plugin uses cron.ParseStandard only to validate a user-entered spec, which is
a library call rather than a driver binding, and the in-process scheduler
already normalizes 5-field specs.
enrichAccessLogsWithUsers preferred the UserService contract over the local
repository — correct layering, but it looped GetUserByID and issued up to a
page-size worth of separate SELECTs against w_users, while the single-query
WHERE id IN variant was only reached in the no-contract fallback branch.
Give the contract a GetUsersByIDs so callers can keep the layering and drop
the N+1. The test asserts 1 query batched against 3 per-id, so the counting
itself is checked.
AppendTaskExecutionLog discarded the error from its read of the buffer, so a
transient cache failure looked like an empty buffer and the very next write
replaced the whole accumulated log with just the newest line. Flush already
distinguished miss from failure; append now does the same.
loadTaskExecutionLog and loadTaskExecutionLogs could never fail, yet four
call sites branched on their error as if they could, presenting unreachable
code as error handling.
parsePositiveInt reported invalidity through a bool that both call sites
discarded, and returned (false, nil) whenever Atoi succeeded on a negative
number. GetLogs therefore accepted ?cursor=-5 and served it as cursor 0
('latest') instead of the documented 400. Validity now travels through the
error result, which no caller can ignore.
Five sites used == against sentinels (redis.Nil, ingest.ErrForbidden,
errs.ErrDatabaseUninitialized). The neighbouring not-found checks already
went through errors.Is helpers, so a wrapped error would silently downgrade
a 403 to a 400 and a 500 to a 400.
- Purify core micro-kernel by removing context hardcoded helpers and reverse dependencies
- Eliminate init() side effects in infra plugins with reversible lifecycle disposal
- Completely isolate plugins by removing cross-plugin imports and using core/contracts
- Introduce TaskService and RiskControlService contracts for unified cross-plugin APIs
- Regenerate Swagger documentation and update developer guide matrix
- Achieve 0 violations in check_cordis_architecture.sh and 100% test pass
- Relocated go.mod and go.sum into backend/ root directory
- Stripped redundant backend/ segments from all Go imports (github.com/Rain-kl/Wavelet/...)
- Unified Makefile, swagger, and build-test to execute in backend/ module context
- Ensured 100% build-test, code-check, format, and swagger pass