Commit Graph

42 Commits

Author SHA1 Message Date
ryan 84eaf3f555 autoresearch iter 19: make task handlers driver-agnostic so they run under both workers
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.
2026-08-29 09:23:01 +08:00
ryan 8c4955c835 autoresearch iter 18: remove the phantom user:daily_audit schedule
The user plugin registered a cron dispatching to user:daily_audit, a task
pattern it never registers, and no audit logic exists anywhere in the plugin.
The daily run therefore went nowhere while a test asserted the schedule was
registered — proving the wiring existed, not that it worked. Implementing a
real daily audit is unstarted functionality, so the schedule is removed rather
than stubbed.

The combined domain test now asserts the real invariant across all applied
plugins: every schedule's task type must have a registered handler.
2026-08-29 09:11:16 +08:00
ryan 1b1c45206c autoresearch iter 17: wire the pairing-code cleanup cron to a real handler
message_gateway scheduled message_gateway:cleanup_pairing_codes every 10
minutes but never registered a task under that pattern, so every dispatch
went to a task type with no handler and expired pairing rows accumulated
forever, even though repository.DeleteExpiredPairingCodes already existed.
Add a test that fails for any schedule whose task pattern is unregistered:
it reports the exact orphan rather than relying on a schedule-exists assert.
2026-08-29 09:03:33 +08:00
ryan 976f9b15ae autoresearch iter 16: add batch user lookup and use it for log enrichment
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.
2026-08-29 08:51:30 +08:00
ryan 2c415638fd autoresearch iter 15: stop CORS from querying the database on every request
isOriginAllowed read server_address from w_system_configs for every request
carrying an Origin header — one uncached primary-DB round-trip plus a split
and trim loop per browser request, while sibling config reads in the storage
driver are already TTL cached. Read it through the shared CacheService with
the same 5s window, falling back to the database when no cache is bound.
driver_http now binds CacheService in Apply the way it already binds DBService.
2026-08-29 08:44:37 +08:00
ryan 6932b54a30 autoresearch iter 14: stop a cache read error from clobbering the buffered task log
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.
2026-08-29 08:38:55 +08:00
ryan 101cb2ff7a autoresearch iter 12: inproc driver reports untracked executions as an error
GetExecution returned (nil, nil) under the in-process driver where the asynq
driver returns an error, so the same contract call meant 'empty' in one
deployment mode and 'failed' in the other.
2026-08-29 08:35:00 +08:00
ryan 3d2038a251 autoresearch iter 11: unimplemented auth mocks fail loudly instead of returning (nil, nil)
Authenticate, CreateAuthSource, UpdateAuthSource and ToggleAuthSource claimed
success with a nil record, so any test that reached them surfaced a nil
pointer dereference instead of the actual cause. Full suite confirms no test
relied on the silent behaviour.
2026-08-29 08:33:16 +08:00
ryan c4068efd54 autoresearch iter 10: keep error identity at the last errorlint sites
RunPushTest flattened channel validation failures with %v, telegram's
fallback path discarded the original send error, and the config loader's
type assertion on viper.ConfigFileNotFoundError would miss a wrapped form
and fatally abort over a merely missing file. errorlint now reports zero.
2026-08-29 08:29:40 +08:00
ryan 22ecafdbc2 autoresearch iter 9: drop always-nil error results from task log loaders
loadTaskExecutionLog and loadTaskExecutionLogs could never fail, yet four
call sites branched on their error as if they could, presenting unreachable
code as error handling.
2026-08-29 08:26:39 +08:00
ryan 18820b17f6 autoresearch iter 8: render synthesized notification content in stable order
bodyContent's fallback ranged over the body map, and Go randomizes map
iteration, so the same notification rendered its fields in a different order
on every send. Observed failing before the fix: the second call already
reordered the output. Iterate sorted keys instead.
2026-08-29 08:23:23 +08:00
ryan c66399eedc autoresearch iter 7: share body field extraction across push channels
email, telegram and lark each re-implemented the title/content/level lookup
with only their markup differing, and each carried a dead content := ""
initialization that every branch overwrote. Three small helpers in template.go
now own that logic.
2026-08-29 08:20:43 +08:00
ryan ce33997c23 autoresearch iter 6: reject negative cursor instead of silently using 0
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.
2026-08-29 08:16:50 +08:00
ryan 381c79417e autoresearch iter 5: recover panics in background cleanup loops
Four long-running goroutines were launched with a bare go statement, so a
panic in any of them took down the whole process: the RAM cache's expired-key
eviction, the batch writer's flush worker, the disk cache cleanup worker and
the PoW memory store sweeper. Route them through util.Go.

The architecture gate only grepped for 'go func(', which is why the named-call
form went unnoticed; widen it to cover both launch styles.
2026-08-29 08:12:27 +08:00
ryan 7e6b9e7c2f autoresearch iter 4: stop one disconnected client from failing a shared image flight
EnsureCompressedImageCache passed the arriving caller's request context into
the singleflight body, which runs once for every concurrent requester of that
cache key. If the first client disconnected, gin canceled the context, the
shared generation aborted, and every follower received that failure and fell
back to the uncompressed original. Detach cancellation with
context.WithoutCancel so trace values still propagate but the shared work
outlives any single requester.
2026-08-29 08:07:19 +08:00
ryan 686e3ef5a6 autoresearch iter 3: share upload-record error mapping via filesrv helper
ServeFileByID and DownloadFile duplicated the lookup failure mapping and
each used an unchecked *strconv.NumError assertion that cannot match a
wrapped error. One helper now classifies 404 vs 400 via errors.As; each
endpoint keeps its own fallback for unclassified failures. ErrInvalidUploadID
became unused once both sites report ErrInvalidFileID for a malformed ID.
2026-08-29 08:02:42 +08:00
ryan 37ad58699d autoresearch iter 2: compare error sentinels with errors.Is
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.
2026-08-29 07:58:59 +08:00
ryan f4975d6732 refactor(plugins): restructure admin and message_gateway into standard layered sub-packages 2026-08-28 22:33:26 +08:00
ryan 0035e548a5 fix(risk_control,message_gateway): fix SQL LIKE escape syntax and use UserService contract 2026-08-28 20:19:24 +08:00
ryan df351cbd33 refactor(core): decouple gin from pkg/util and reduce code duplication 2026-08-28 20:15:47 +08:00
ryan c52b7c4abf test(upload): move storage task fixtures to in-memory mock 2026-08-28 18:54:23 +08:00
ryan 4d6be2fa77 fix(drivers): propagate app-lifetime context through inproc cron/worker drivers
cron 触发与 worker 执行的任务现在继承应用生命周期 context(关闭时级联取消,带超时子上下文),
替代裸 context.Background()。contextcheck 清零。
lint_issues 26→24
2026-08-28 17:04:44 +08:00
ryan 867fcb2288 refactor: revive cleanup — unused params to _, add missing doc comments
- admin/db_helper GetCache/GetUserService/GetAuthService: ctx -> _ (签名对称保留)
- validateMergedStorageConfig / ParseMigrationTargetConfig / MockStorageService.Put 未用参数 -> _
- SetDBServiceForTest、StorageDriver 常量组补充文档注释
lint_issues 33→26
2026-08-28 16:53:32 +08:00
ryan 6e12a7fd5d fix(admin): propagate cache errors in FlushTaskExecutionLog
缓存故障(非 ErrCacheMiss)不再被静默吞掉:上抛包装错误,避免缓冲任务日志丢失并误报持久化成功;
ErrCacheMiss 仍视为无日志的正常路径。附 3 个回归测试(故障/未命中/持久化+清理)。
lint_issues 34→33 (nilerr 清零)
2026-08-28 16:50:03 +08:00
ryan cf85a56aa7 refactor: eliminate string/magic-number literals (goconst, mnd) and fix const-type grouping (SA9004)
- upload/task: taskCategoryUpload/taskQueueDefault 常量替代 8 处字面量
- admin: 复用既有 logDBNameSQLite 常量替代 3 处 "sqlite" 字面量
- pkg/cache/disk: defaultCleanupInterval 命名常量
- driver_asynq_worker/executor: 分离 contextKey 类型常量组
lint_issues 45→34, tests 44/44
2026-08-28 16:38:18 +08:00
ryan 528240026d chore(lint): unify formatting on golangci-lint fmt (gofumpt), uncap issue reporting, fix gofumpt drift
- make format 现在与 code-check 使用同一格式化器(golangci-lint fmt),消除 goimports -local 与 gofumpt 的格式拉锯
- .golangci.yml 关闭默认 50/3 截断,完整上报所有问题(只增强不弱化)
- 全库 gofumpt 规范化(203 files, 纯格式无行为变更)
2026-08-28 16:31:53 +08:00
ryan 3a61c38dc5 fix(core): delegate driver and task extension lookups to root context and improve test reliability 2026-08-28 16:09:18 +08:00
ryan 3df621637f fix(db): ensure sqlite data directory exists before opening database 2026-08-28 15:42:24 +08:00
ryan 692b4b4851 feat(db): split migrations into dialect-specific sqlite and postgres packages 2026-08-28 15:36:03 +08:00
ryan 06508b6f13 refactor(drivers): decouple inproc cron from inproc worker and satisfy linter 2026-08-28 15:17:11 +08:00
ryan e434e6dc0a feat(drivers): provide TaskService implementation in inproc worker 2026-08-28 15:14:27 +08:00
ryan 25647df3cf feat(drivers): implement in-process cron scheduler driver plugin 2026-08-28 15:13:24 +08:00
ryan d8e69bb31b feat(drivers): implement in-process async worker driver plugin 2026-08-28 15:12:42 +08:00
ryan 98d2c1cbd0 feat(infra): implement zero-dependency pure in-memory cache plugin 2026-08-28 15:11:46 +08:00
ryan 299ac30ee4 refactor(core): align with cordis spatiotemporal composability architecture
- 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
2026-08-28 15:05:31 +08:00
ryan 48211fa587 chore: code-check 2026-08-28 13:42:49 +08:00
ryan 9213ee79b3 refactor(core): finalize context test and standalone repository fallback 2026-08-28 13:38:22 +08:00
ryan a296818922 refactor(user): decouple repository from direct database infra import 2026-08-28 13:37:13 +08:00
ryan e19bf36580 refactor(core): align architecture with cordis spatiotemporal composability 2026-08-28 13:28:58 +08:00
ryan 9f8890d159 refactor(module): simplify module name to Wavelet and standardize import paths
- Declared module Wavelet in backend/go.mod
- Replaced github.com/Rain-kl/Wavelet/ with clean Wavelet/ import paths across backend codebase
- Updated architecture guards, Makefile, swagger, and build tests
- 100% passed all tests, lint checks, and binary compilation
2026-08-28 13:10:30 +08:00
ryan f2ab94501c refactor(layout): relocate go.mod to backend/ and clean import paths to module root
- 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
2026-08-28 13:01:51 +08:00
ryan 43dc97e48c refactor(layout): consolidate backend codebase into backend/ package and clean root directory
- Moved cmd/, core/, plugins/, pkg/, downstream/, and main.go into backend/ directory
- Batch updated all Go source files to import github.com/Rain-kl/Wavelet/backend/...
- Updated Makefile, scripts/swagger.sh, architecture guards, and platform skills
- Passed all quality gates (100% tests, 0 lint issues, clean build)
2026-08-28 12:56:02 +08:00