cd843465b2f0efc943082848053be01fa9ae4ede
817 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2c4aabe961 |
docs: rewrite README for BoosAPI rebranding
- Replace all Metapi references with BoosAPI - Remove external service links (GitHub, Docker Hub, Render, Zeabur) - Simplify structure for self-hosted deployment - Update both Chinese and English versions Signed-off-by: Boos4721 <boos4721@icloud.com> |
||
|
|
9cfe8427b5 |
feat: rebrand Metapi to BoosAPI, add ComfyUI agent and user management
CI / Detect Docs Changes (push) Has been cancelled
CI / Test Core (push) Has been cancelled
CI / Build Web (push) Has been cancelled
CI / Build Server (push) Has been cancelled
CI / Build Desktop (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Repo Drift Check (push) Has been cancelled
CI / Schema Check (SQLite) (push) Has been cancelled
CI / Schema Check (MySQL) (push) Has been cancelled
CI / Schema Check (Postgres) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Audit Production Dependencies (push) Has been cancelled
CI / Publish Docker Image (amd64) (push) Has been cancelled
CI / Publish Docker Image (arm64) (push) Has been cancelled
CI / Publish Docker Image (armv7) (push) Has been cancelled
CI / Publish Docker Manifest (push) Has been cancelled
CodeQL / Analyze (JavaScript/TypeScript) (javascript-typescript) (push) Has been cancelled
- Rename project from Metapi to BoosAPI across all UI and server strings - Add ComfyUI conversational agent page (/comfyui-agent) - Add user management system (register, login, API keys, admin) - Update Dockerfile and database schema - Add ComfyUI workflow nodes support - Update shared contracts and platform configurations Signed-off-by: Boos4721 <boos4721@icloud.com> |
||
|
|
cdb12a9819 |
[codex] fix quota refresh probe model (#490)
CI / Detect Docs Changes (push) Has been cancelled
CI / Test Core (push) Has been cancelled
CI / Build Web (push) Has been cancelled
CI / Build Server (push) Has been cancelled
CI / Build Desktop (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Repo Drift Check (push) Has been cancelled
CI / Schema Check (SQLite) (push) Has been cancelled
CI / Schema Check (MySQL) (push) Has been cancelled
CI / Schema Check (Postgres) (push) Has been cancelled
CI / Build Docs (push) Has been cancelled
CI / Audit Production Dependencies (push) Has been cancelled
CI / Publish Docker Image (amd64) (push) Has been cancelled
CI / Publish Docker Image (arm64) (push) Has been cancelled
CI / Publish Docker Image (armv7) (push) Has been cancelled
CI / Publish Docker Manifest (push) Has been cancelled
CodeQL / Analyze (JavaScript/TypeScript) (javascript-typescript) (push) Has been cancelled
Docs Pages / Build Docs (push) Failing after 2m53s
Docs Pages / Deploy Docs (push) Has been skipped
|
||
|
|
f19ddac865 |
feat: 支持从站点页快捷添加 API Key (#505)
Co-authored-by: juzi <956428403@qq.com> |
||
|
|
90e2f0c405 |
Merge PR #535: clear production dependency audit
Merge the narrow package-lock refresh that restores the main production audit gate. |
||
|
|
0f51dec36e |
Clear the main-branch production audit gate
Constraint: main push CI fails on npm audit --omit=dev --audit-level=high after recent merges. Rejected: Broad npm audit fix output | it updated unrelated dev-only lockfile entries. Confidence: high Scope-risk: narrow Directive: Keep PR audit informational until production dependencies are audited on dev/main consistently. Tested: ELECTRON_SKIP_BINARY_DOWNLOAD=1 npm ci --prefer-offline --no-audit --no-fund; npm audit --omit=dev --audit-level=high; npm run typecheck:server; npm test -- --run src/server/config.test.ts src/server/settingsRoutePayloads.test.ts Not-tested: Full GitHub Actions matrix before opening PR. |
||
|
|
f4148675e1 |
Merge PR #510: per-site model probe
Merged after updating the PR onto current main and fixing the remaining probe-setting review gaps.\n\nValidation:\n- GitHub checks all passing: Test Core, Typecheck, Build Web/Server/Desktop, Repo Drift Check, Schema SQLite/MySQL/Postgres, CodeQL, CodeRabbit.\n- Local: npm run typecheck\n- Local: npm run repo:drift-check\n- Local: npx vitest run --root . src/server/db/schemaContract.test.ts src/server/db/schemaArtifactGenerator.test.ts src/server/db/schemaIntrospection.test.ts src/server/db/schemaParity.test.ts src/web/api.test.ts src/web/pages/helpers/sitesEditor.test.ts src/web/pages/sites.disabled-models-save.test.tsx src/web/pages/sites.edit-scroll.test.tsx |
||
|
|
e5a8a0b3d7 |
Keep per-site probe settings reliable before merge
Refresh the PR onto current main and close the remaining probe-setting review gaps: the primary site save now persists the latency threshold, the site row type carries that field without an any-cast, active probe streams are aborted on unmount, and all-model one-shot probes get the longer timeout they need. Constraint: PR #510 must preserve the per-site model probe feature while merging cleanly into current main. Rejected: Leave threshold persistence behind the separate probe-settings button | the primary save path would still silently drop user changes. Rejected: Keep the SiteRow any-cast | it hides API/schema drift for the new persisted field. Confidence: high Scope-risk: narrow Directive: Keep probe setting fields represented in the typed site save payload and covered by focused web API/editor tests. Tested: npm run typecheck; npm run repo:drift-check; npx vitest run --root . src/server/db/schemaContract.test.ts src/server/db/schemaArtifactGenerator.test.ts src/server/db/schemaIntrospection.test.ts src/server/db/schemaParity.test.ts src/web/api.test.ts src/web/pages/helpers/sitesEditor.test.ts src/web/pages/sites.disabled-models-save.test.tsx src/web/pages/sites.edit-scroll.test.tsx Not-tested: Full npm test. |
||
|
|
1d61a7ac84 |
Merge PR #495: auto-discover recent Docker Hub dev tags
Merged after resolving conflicts with current main.\n\nValidation:\n- GitHub checks all passing: Test Core, Typecheck, Build Web/Server/Desktop, Repo Drift Check, Schema checks, CodeQL, CodeRabbit.\n- Local: npx vitest run --root . src/web/pages/settings/UpdateCenterSection.test.tsx src/server/services/updateCenterVersionService.test.ts src/server/routes/api/updateCenter.test.ts src/server/services/updateCenterStatusService.test.ts\n- Local: npm run typecheck\n- Local: npm run repo:drift-check |
||
|
|
93bc42a69d |
Refresh the recent Docker tag PR onto current main
The release branch had fallen behind current main and only conflicted in the Update Center recent-tag test. Keep the latest main-side deploy-state coverage while preserving the PR's raw-tag filtering and digest visibility assertions. Constraint: PR #495 must merge into the current main without widening the PR diff beyond the update-center candidate behavior. Rejected: Drop the PR-specific digest/raw-tag assertions | would regress the review fixes that prompted the branch update. Confidence: high Scope-risk: narrow Directive: Keep recent Docker tag cards deployable only from real tagName values and keep digest metadata visible before deployment. Tested: npx vitest run --root . src/web/pages/settings/UpdateCenterSection.test.tsx src/server/services/updateCenterVersionService.test.ts src/server/routes/api/updateCenter.test.ts src/server/services/updateCenterStatusService.test.ts; npm run typecheck; npm run repo:drift-check; git diff --cached --check origin/main Not-tested: Full npm test. |
||
|
|
508fa71ec7 |
Merge pull request #518 from kevinye13/fix/settings-allowlist-json-array
fix(settings): persist model allowlist as JSON array |
||
|
|
3ce705ab9d | Update contributors section in README.md | ||
|
|
4481cf7493 |
Clean up contributor section in README
Removed unnecessary contributor images from the README. |
||
|
|
3720b3d0ed |
Merge pull request #533 from cita-777/release/fix-protocol-compatibility-20260508
[fix] Harden protocol compatibility from dev |
||
|
|
10dc1ba7bd |
Carry update center review test follow-up
This merge keeps PR #533 aligned with dev after addressing CodeRabbit follow-up test comments. The changes are limited to UpdateCenterSection test assertions. Constraint: Release branch remains the publication branch for the open main-targeting PR. Confidence: high Scope-risk: narrow Tested: npx vitest run --root . src/web/pages/settings/UpdateCenterSection.test.tsx Tested: npm run typecheck:web Co-authored-by: OmX <omx@oh-my-codex.dev> |
||
|
|
fee6a6388f |
Tighten update center review test coverage
CodeRabbit follow-up review pointed out that one renderer assertion could not fail usefully and that the new recent-candidate deploy test did not prove log streaming after dispatch. The test now asserts the visible candidate text directly and covers streamUpdateCenterTaskLogs for the new deploy path. Constraint: Keep review follow-up scoped to test coverage only. Confidence: high Scope-risk: narrow Tested: npx vitest run --root . src/web/pages/settings/UpdateCenterSection.test.tsx Tested: npm run typecheck:web Co-authored-by: OmX <omx@oh-my-codex.dev> |
||
|
|
00348e0528 |
Carry protocol review fixes into release
The release branch is main-based and tracks the reviewed dev slice for PR publication. This merge carries the post-review compatibility fixes without rewriting the already-open PR history. Constraint: PR #533 publishes dev changes through a clean release branch targeting main. Rejected: Recreate the PR branch from scratch | unnecessary churn after green checks and review context already exist. Confidence: high Scope-risk: narrow Tested: npx vitest run --root . src/server/proxy-core/responsesPreflight.test.ts src/server/proxy-core/serviceTierPolicy.test.ts src/server/routes/proxy/chat.stream.test.ts src/web/pages/settings/UpdateCenterSection.test.tsx Tested: npm run typecheck:server Tested: npm run typecheck:web Tested: npm run repo:drift-check Co-authored-by: OmX <omx@oh-my-codex.dev> |
||
|
|
8309ac073a |
Close protocol compatibility review gaps
Review feedback found narrow compatibility regressions in the web-search shim, Responses tool detection, service tier accounting, and update-center Docker candidate actions. The fix keeps synthetic search routed through the dedicated search model, preserves Responses text compatibility, distinguishes absent service_tier from filtered service_tier, and evaluates recent Docker tags per candidate. Constraint: Review fixes must stay on dev first, then flow into the main-based release PR branch. Rejected: Leave Responses web_search simulation on the request model | it has the same search-route selection risk as Anthropic simulation. Confidence: high Scope-risk: narrow Tested: npx vitest run --root . src/server/proxy-core/responsesPreflight.test.ts src/server/proxy-core/serviceTierPolicy.test.ts src/server/routes/proxy/chat.stream.test.ts src/web/pages/settings/UpdateCenterSection.test.tsx Tested: npm run typecheck:server Tested: npm run typecheck:web Tested: npm run repo:drift-check Co-authored-by: OmX <omx@oh-my-codex.dev> |
||
|
|
207ab5cedf | Prepare protocol compatibility release | ||
|
|
2491a9af5a |
Harden cross-protocol request compatibility
Several downstream clients send non-cache compatibility fields across Chat, Responses, Anthropic Messages, and Responses WebSocket surfaces. The proxy now normalizes legacy functions/function_call, maps web_search tools across protocols, rejects unsupported HTTP Responses continuation shapes before upstream dispatch, and applies configurable service_tier policy consistently before requests leave the server. Constraint: Publication flow keeps day-to-day commits on dev and opens main PRs from a release branch. Constraint: No new dependencies; web_search-only simulation reuses the existing local search route. Rejected: Forward external HTTP previous_response_id to strict upstreams | it produces ambiguous continuation failures and stale retry behavior outside WebSocket state. Rejected: Add a dedicated search dependency | existing /v1/search route is sufficient for synthetic server-tool responses. Confidence: high Scope-risk: moderate Directive: Keep Responses HTTP continuation checks aligned with WebSocket continuation support before relaxing these guards. Tested: npm run typecheck:server Tested: npx vitest run --root . src/server/proxy-core/responsesPreflight.test.ts src/server/proxy-core/serviceTierPolicy.test.ts src/server/test-fixtures/protocol/non-cache-field-matrix.test.ts src/server/transformers/openai/responses/conversion.test.ts src/server/transformers/anthropic/messages/conversion.test.ts src/server/routes/proxy/chat.stream.test.ts src/server/routes/proxy/responses.codex-oauth.test.ts Tested: npx vitest run --root . src/server/routes/proxy/responses.websocket.test.ts Tested: npm run repo:drift-check Not-tested: Full application build and full Vitest suite Co-authored-by: OmX <omx@oh-my-codex.dev> |
||
|
|
a53c62885b | fix(settings): persist model allowlist as JSON array | ||
|
|
99392341fe |
fix: handle empty-string column defaults in MySQL schema introspection
MySQL information_schema.COLUMNS.COLUMN_DEFAULT stores DEFAULT '' as an empty string, not NULL. normalizeDefaultValueForColumn was treating any empty rawDefaultValue as 'no default' and returning null, causing the MySQL schema parity test to see defaultValue: null for post_refresh_probe_model while schemaContract.json (generated from TypeScript schema) had "''". Fix: when rawDefaultValue is empty string, return "''" for text/json columns instead of null, so the round-trip through MySQL introspection matches the contract. |
||
|
|
078ac4aa9d |
fix: add statement-breakpoint to migration 0025 and regenerate upgrade SQL
Better-SQLite3 requires --> statement-breakpoint between each statement in a migration file; without it all statements are passed as a single string to Database.prepare() which throws RangeError on multi-statement input. |
||
|
|
cb5078468c |
fix: address CodeRabbit review for per-site probe
- Fix SSE abort: propagate AbortSignal to worker pool; close connection
immediately on client disconnect without sending 'complete' event
- Fix Boolean coercion: use strict === true/=== 1 check instead of Boolean()
to avoid Boolean('false') === true foot-gun
- Fix probe-now: parse and forward latencyThresholdMs from request body
- Fix api.ts probeSiteNow: add latencyThresholdMs to options type
- Fix backup import: restore postRefreshProbe* fields when inserting sites
so that backup/restore round-trips preserve per-site probe config
- Fix latency threshold persistence: add postRefreshProbeLatencyThresholdMs
column (migration 0026), save/load it in site editor, pass to
runPostRefreshProbeIfEnabled so auto-probe also respects the threshold
- Fix state management: setProbeCompleted(false) at probe start; error
branch also refreshes model lists and sets probeCompleted to show results
- Regenerate schema artifacts (mysql/postgres bootstrap+upgrade, contract)
|
||
|
|
37924751f6 |
chore(db): add migration and regenerate schema artifacts for per-site probe columns
- Add drizzle/0025_site_post_refresh_probe.sql (ALTER TABLE sites ADD 3 columns) - Update drizzle/meta/_journal.json (idx=24 entry) - Regenerate mysql/postgres bootstrap+upgrade SQL and schemaContract.json |
||
|
|
46f23ddbb3 |
feat(sites): per-site model probe with streaming logs and auto-disable
- Move post-refresh probe settings from global config to per-site (sites table) - Add manual 'probe now' button in site editor with real-time SSE log stream - Use fetch+ReadableStream instead of EventSource to support Authorization header - Concurrent probe execution (default 10 workers) via worker-pool pattern - Add stop button to cancel in-flight probe while preserving completed results - Add latency threshold: auto-disable models exceeding response time limit - Treat inconclusive probe results as unsupported (auto-disable) - Show specific failure reason in logs (timeout, no token, model not found, etc.) - Refresh and display post-probe model status list (green=available, red=disabled) - Remove probe settings from global Settings page and RuntimeSettingsPayload |
||
|
|
fa6edec83a |
Keep recent Docker tag deploys explicit and tag-safe
Review feedback pointed out two small but important operator-facing gaps in the recent-tag card: one-click deploy should only be available when a real raw Docker tag exists, and the digest that will be deployed should be visible on the card instead of remaining implicit. This patch tightens the candidate filter to require tagName and renders the digest metadata before the deploy actions, with regression coverage for both behaviors. Constraint: The deploy API still requires a raw Docker tag, not a normalized display value Constraint: The recent-tag card should surface the exact digest operators are about to deploy Rejected: Keep accepting normalizedVersion-only candidates | could enable one-click deploy with a non-tag display value Rejected: Rely on displayVersion alone for digest visibility | digest presence should stay explicit even if display text changes later Confidence: high Scope-risk: narrow Reversibility: clean Directive: Any future recent-tag UI should treat tagName as the deployable identity and digest as separately visible metadata Tested: src/web/pages/settings/UpdateCenterSection.test.tsx, npm run typecheck, git diff --check Not-tested: Full PR checks rerun pending after push |
||
|
|
93912bb330 |
Publish the dev-tag discovery upgrade to main on a clean release branch
This release branch snapshots the latest dev work onto current main so the update center can surface recent non-stable Docker tags without operators looking them up manually. The branch keeps stable Docker discovery as the primary path while carrying the new recent-tag auto-discovery, UI affordances, and regression coverage through the repo's release flow. Constraint: Publication must start from latest origin/main and merge origin/dev on a clean release branch Constraint: Stable Docker Hub discovery semantics must remain intact while adding recent non-stable discovery Rejected: Re-open or reuse the already-merged PR #494 branch | it has already been absorbed by main and deleted remotely Rejected: Publish directly from dev | repo workflow requires a clean release branch to main Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep future dev-tag publication work on fresh release branches cut from origin/main; do not revive merged release branches Tested: Focused update-center vitest suite, npm run typecheck, npm run repo:drift-check, npm run build:web, npm run docs:build, git diff --check (release branch) Not-tested: Full npm test remains red because tmp/sub2api frontend suites are still broken in this repo snapshot |
||
|
|
c94e3148dd |
Let operators deploy recent dev Docker tags without manual lookup
The update center already allowed manual Docker tag deploys, but operators still had to know and paste dev or branch tags by hand. This change keeps the stable Docker Hub candidate as the main path while automatically surfacing the most recent non-stable tags and their digests for one-click deployment. Constraint: Stable Docker Hub discovery must remain the default candidate path Constraint: Existing deploy API and helper protocol should stay unchanged Rejected: Promote dev tags into the primary stable candidate slot | would blur stable and experimental release semantics Rejected: Add a brand new backend deploy endpoint for recent tags | existing targetTag/targetDigest deploy path already covers the need Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep stable and recent non-stable Docker tag discovery distinct unless product semantics deliberately change Tested: Focused vitest for update-center services/routes/UI, npm run typecheck, npm run repo:drift-check, npm run build:web, npm run docs:build, git diff --check Not-tested: Full npm test remains red because tmp/sub2api frontend suites are still broken in this repo snapshot |
||
|
|
262651a708 |
Merge pull request #494 from cita-777/release/feat-update-center-dev-tags-20260417
[chore] publish dev snapshot to main |
||
|
|
4a57e312f5 |
Align outbound fallback expectations with the reviewed Responses id shape
The last CI failure after the review cleanup was only a stale test expectation: function_call fallback items now correctly use fc_* item ids while preserving the call_* id in call_id. Updating the test keeps the suite aligned with the Responses payload shape we intentionally adopted in the bridge. Constraint: Keep the fix to the assertion only; the production behavior already matches the reviewed contract Rejected: Revert the fc_* item id change | that would reopen the review thread we intentionally fixed Confidence: high Scope-risk: narrow Directive: When bridge output semantics change intentionally, update sibling facade tests in the same PR so CI reflects the new contract immediately Tested: Focused vitest for openai responses outbound/response bridge, Gemini request bridge, Settings payload rules; typecheck; git diff --check Not-tested: Full npm test |
||
|
|
544324ed0a |
Restore the full payload-rule protocol list in Settings
One last review thread caught a real UI regression: the visual payload-rule editor had drifted away from the shared protocol option source and no longer exposed several active platform targets. Rebinding the dropdown to the shared option list fixes the regression without inventing another source of truth. Constraint: The fix should reuse the existing shared option list instead of creating another hardcoded protocol subset Rejected: Expand the inline array manually | would repeat the same drift problem that caused the regression Confidence: high Scope-risk: narrow Directive: Payload-rule protocol selectors should always read from the shared option source so Settings and the payload-rule parser stay aligned Tested: settings.payload-rules vitest; typecheck; git diff --check Not-tested: Full npm test |
||
|
|
1f464dc03d |
Close out the last review edge-cases before final merge
The remaining review threads were down to route alias hygiene, proxy-safe header ordering, and a Gemini canonical tool-result mismatch. This commit makes the alias/websocket behavior explicit, preserves contributor helper safety, and teaches the canonical Gemini path to recover tool names and wrap function results the same way the OpenAI-shaped path already does. Constraint: Keep the last review fixes limited to the current branch so the release PR stays easy to reason about Rejected: Defer the Gemini canonical fix to a later refactor | the review found a real functional mismatch and the fix stayed localized to the request bridge Confidence: high Scope-risk: narrow Directive: Keep canonical-to-provider bridges internally consistent; if one path resolves tool names or wraps results, the sibling path should not diverge silently Tested: Focused vitest for Gemini request bridge, route aliases, upstream request builder, responses response bridge, contributor updater; typecheck; git diff --check Not-tested: Full npm test; any broader end-to-end Gemini live-provider behavior outside the covered bridge tests |
||
|
|
20f06d391c |
Tighten alias and header edge-cases called out in review
The latest review pass found a few more concrete edge-cases that were still cheap to close: invalid /responses aliases could still rewrite typos, websocket session headers should prefer proxy-safe dashed forms, contributor rendering needed an input guard, and several upstream request/response helpers still had small contract mismatches around Accept/beta handling and synthesized tool ids. These fixes keep the release branch behavior explicit while the PR remains open. Constraint: Keep changes surgical and well-covered so the review cleanup does not destabilize the already-green release branch Rejected: Leave these for post-merge cleanup | they were still active review threads with straightforward fixes Confidence: high Scope-risk: narrow Directive: When alias routes exist only for ergonomics, reject unknown subpaths loudly instead of silently rewriting them Tested: Focused vitest for contributor updater, route aliases, upstream request builder, openai responses response bridge; typecheck; git diff --check Not-tested: Full npm test; the remaining Gemini review thread that likely needs a broader canonical-tool-result contract decision |
||
|
|
e795f22367 |
Settle the last concrete review regressions on the release branch
A few review threads still pointed at real behavior mismatches: Anthropic tool JSON deltas were still trimming whitespace, Responses conversion still raised low token caps to the floor, and the bare /responses GET alias returned upgrade messaging that did not match the actual websocket entrypoint. This commit makes those behaviors explicit and locks them with focused tests. Constraint: Keep the release branch green while fixing only the review findings that have a clear, testable contract Rejected: Leave these for a follow-up cleanup PR | they were low-diff and directly blocked comment resolution on the current release PR Confidence: high Scope-risk: narrow Directive: Preserve raw stream delta text unless a downstream protocol explicitly requires normalization; whitespace can be semantic in incremental payloads Tested: Focused vitest for anthropic stream bridge, responses conversion, route aliases; typecheck; git diff --check Not-tested: Full npm test; the remaining review threads that still need broader product decisions |
||
|
|
02520255db |
Clear remaining low-risk review debt on the release branch
The PR still had a few targeted review threads around contributor pagination, route-layer passthroughs, dead header fallbacks, and synthetic response ids. These are small enough to settle directly on the release branch without broadening the merge scope, and they tighten the repo back toward the service-owned boundaries this refactor is aiming for. Constraint: Keep the changes narrow and regression-covered so the release PR stays green while review threads are closed out Rejected: Leave the minor threads for follow-up after merge | they were isolated enough to fix now and would keep noise on the PR Confidence: high Scope-risk: narrow Directive: When a route shim stops serving any route-local behavior, point callers at the owning service instead of keeping a passthrough around Tested: Focused vitest for contributor updater, openai responses response bridge, upstream request builder, stats proxy logs, architecture boundaries; typecheck; repo drift check; git diff --check Not-tested: Full npm test; unresolved review threads that still require larger product decisions |
||
|
|
4b5d045b00 |
Address high-priority review gaps before merging the dev snapshot
The release branch still had unresolved review comments around payload-rule atomicity, brand blocking, compact fallback controls, and response compatibility edge-cases. This patch pulls those behaviors back in line with the intended contracts and adds focused regression coverage for the fragile bridges. Constraint: The fixes must stay narrow to the PR branch so review/merge can continue without reopening the larger dev snapshot conflict set Rejected: Leave outdated-looking threads unresolved until after merge | reviewers still see concrete unfixed regressions in the current release branch Rejected: Re-run another broad merge from dev/main | too risky while the PR branch is already green and mergeable Confidence: medium Scope-risk: moderate Directive: If these release-branch fixes need to persist for future release cuts, backport them onto dev instead of re-fighting the same review threads next time Tested: Focused vitest for settings events, brand matcher, compact responses, codex compatibility, anthropic stream bridge, openai chat response bridge; typecheck; repo drift check; git diff --check Not-tested: Full npm test; live PR thread resolution state after push |
||
|
|
57db7fd107 |
Keep PR audit informational without leaving the check red
The CI workflow already described production dependency audit as an informational PR signal, but the job still surfaced as a failing check. That left release PRs in an unstable state even after the real merge-gate jobs were green. This keeps PR audits visible as warnings while still letting main-branch pushes fail if production dependency audit actually returns a non-zero exit. Constraint: Preserve production audit visibility while avoiding false-red PR status Rejected: Remove audit from CI entirely | loses vulnerability visibility Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep audit informational on pull requests unless branch protection is intentionally tightened later Tested: YAML parse via ruby; git diff --check Not-tested: Full GitHub Actions rerun pending after push |
||
|
|
4aa888e581 |
Repair release-branch CI after folding dev onto main
The release branch inherited a few merge-shaped regressions after the large dev snapshot was layered onto the latest main snapshot. This commit restores the main-compatible stats and TokenRoutes behavior the CI suite expects and adds the missing multi-brand helper export so the release branch reflects a coherent post-merge tree instead of a partially regressed hybrid. Constraint: Must keep the release branch mergeable to main while preserving the current publish snapshot shape Rejected: Re-open the whole release merge and hand-resolve every file again | too broad for targeted CI repair Confidence: medium Scope-risk: narrow Reversibility: clean Directive: When dev and main have drifted heavily, re-run the main-facing CI tests after any conflict normalization pass Tested: targeted vitest suite for failing CI jobs plus update-center coverage; typecheck Not-tested: Full npm test still not representative locally because of unrelated untracked tmp/sub2api suites outside the PR branch content |
||
|
|
f335a330e3 |
Prepare the dev snapshot for main review on a clean release branch
This release branch starts from the latest origin/main and folds in the current origin/dev snapshot so the PR to main can follow the repo's publish flow without opening directly from dev. Conflict-heavy files were normalized back to the dev snapshot where necessary so the release branch reflects the code currently being carried on dev instead of a line-merged hybrid. Constraint: Publication flow requires a clean release branch from latest origin/main rather than a PR directly from dev Constraint: The branch must preserve the current dev snapshot even when main and dev have drifted substantially Rejected: Open the PR directly from dev | violates the repo publication flow Rejected: Manually redesign every historic dev/main conflict during release prep | too broad for a publish branch Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Treat this branch as a publication snapshot of dev-on-top-of-main, not as a general cleanup pass over old divergence Tested: update-center focused vitest suite on release branch; typecheck; build:web; docs:build; repo:drift-check Not-tested: Full npm test remains red from inherited tmp/sub2api frontend suites and an existing firstByteTimeout unhandled error |
||
|
|
87fb5149e6 |
Let operators deploy dev Docker Hub tags from the update center
The update center previously surfaced stable Docker Hub candidates but left dev and branch-tag rollouts stranded in SSH and Helm commands. This adds a repo-native manual Docker tag entrypoint in Settings so operators can deploy dev, branch, temporary, or sha tags through the existing helper flow without changing the backend deploy contract. Constraint: Keep the existing helper API and digest-aware Helm contract unchanged Constraint: Preserve stable Docker Hub candidate discovery for default reminders Rejected: Expand automatic Docker Hub discovery to all branch tags | would blur stable release reminders with operator-only rollout targets Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep automatic candidate detection stable-first; manual tag deploy is the escape hatch for non-stable tags Tested: update-center focused vitest suite; typecheck; build:web; docs:build; repo:drift-check Not-tested: Full npm test remains red due to unrelated tmp/sub2api frontend suites and an existing firstByteTimeout unhandled error |
||
|
|
f67ade2e59 |
Keep dev green after moving the active worktree snapshot
The transferred dev snapshot was not publication-ready yet: full tests still failed because worktree-local docs resolution assumed a repo-root node_modules tree, some protocol expectations no longer matched the refactored request bridges, oauth/account-token route tests reused stale modules after resetting DATA_DIR, and model discovery still fired unawaited default-token writes. This follow-up makes the moved dev branch self-consistent and green again by stabilizing module/test isolation, awaiting token mirroring writes, and aligning narrow tests with the current transformer and request-builder contracts. Constraint: The fix set had to stay narrow and unblock the new dev branch without reworking the broader transferred refactor Rejected: Revert the transferred snapshot | would lose the user's requested dev-branch continuation point Confidence: medium Scope-risk: moderate Reversibility: clean Directive: If more DATA_DIR-scoped API test files start flaking under shared workers, reset modules before importing singleton db/config modules instead of relying on process env mutation alone Tested: git diff --check; npm run typecheck; npm run repo:drift-check; npm test Not-tested: Live OAuth/provider flows outside the mocked test harness |
||
|
|
88f40e91f7 |
Preserve the active worktree snapshot on dev for follow-on integration
The root checkout already contained a large in-progress proxy, transformer, and settings refactor. This commit captures that exact work on a dedicated local dev branch without disturbing the original dirty worktree, so the changes can be continued or split from dev instead of living only as uncommitted state. Constraint: The source checkout was already dirty on another branch, so the move had to preserve that worktree while excluding local .idea and .omx residue from the commit Rejected: Switch the dirty root checkout directly to dev | risked disrupting the original branch and in-progress state Confidence: medium Scope-risk: broad Reversibility: clean Directive: Treat this as a transfer snapshot; fix the failing oauth/accountTokens/normalized/docs test regressions before merge or publication Tested: git diff --check; npm run typecheck; npm run repo:drift-check Not-tested: Clean test pass; npm test currently fails in oauth routes, accountTokens sync, shared normalized helpers, gemini route expectations, architecture-boundaries, and docs vitepress config |
||
|
|
a2c2ae614a |
[codex] expose more payload-rule upstream types (#474)
* Expose more payload-rule upstream types in Settings The first payload-rules UI only offered a narrow set of protocol labels, which made live troubleshooting confusing once real playground traffic routed through platforms like sub2api instead of codex. This expands the selectable upstream types, extracts the option list into one small helper, and renames the field to 上游类型 so the UI matches what the runtime matcher actually uses. Constraint: Must preserve the existing payload-rules schema key (`protocol`) even though the UI wording is now upstream-type oriented Rejected: Leaving the dropdown codex/openai-only and telling operators to hand-edit JSON | too easy to misconfigure during live routing diagnosis Confidence: high Scope-risk: narrow Reversibility: clean Directive: If new canonical site platforms are added, update payloadRuleProtocolOptions.ts so the visual editor stays aligned with runtime matching Tested: npx vitest run --root . src/web/pages/settings.payload-rules.test.tsx src/web/pages/settings.payload-rule-platform-options.test.ts Tested: npm run typecheck:web Tested: npm run typecheck:web:test Tested: npm run repo:drift-check Not-tested: Manual dropdown interaction in a browser * Keep payload-rule upstream types aligned with one-api backend support Code review caught that the visual editor still omitted one-api even though the backend continues to treat it as a valid upstream platform. This adds the missing option and extends the focused option-set test so operators can create payload rules for one-api without dropping to raw JSON. Constraint: Must preserve the runtime payload-rules schema and only close the UI/backend option gap Rejected: Removing one-api from the backend in this PR | unrelated behavioral change and broader migration risk Confidence: high Scope-risk: narrow Reversibility: clean Directive: When backend platform support changes, update payloadRuleProtocolOptions.ts and its focused test in the same PR Tested: npx vitest run --root . src/web/pages/settings.payload-rules.test.tsx src/web/pages/settings.payload-rule-platform-options.test.ts Tested: npm run typecheck:web Tested: npm run typecheck:web:test Tested: npm run repo:drift-check Not-tested: Manual browser check of the expanded dropdown list |
||
|
|
9c766dec1c |
[codex] add payload rules settings UI (#473)
* Make payload request overrides configurable from Settings The payload-rules engine already existed in the proxy path, but operators had no supported runtime UI to manage CPA-style overrides. This wires the setting through the runtime settings API, adds strict validation, and ships a low-friction visual editor with an advanced JSON fallback so common cases like Codex high reasoning can be configured without hand-editing backend state. Constraint: Must reuse the existing payload-rules execution path and settings table without schema changes Constraint: Must fit the existing metapi Settings-page patterns rather than introducing a standalone config surface Rejected: JSON-only editor as the primary UX | too long and too easy to misconfigure for common cases Rejected: A brand-new backend rule format for the UI | would duplicate the existing payload-rules source of truth Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep visual-rule serialization and advanced JSON editing in sync before extending the rule model Tested: npm run typecheck Tested: npx vitest run --root . src/server/services/payloadRules.test.ts src/server/routes/api/settings.events.test.ts src/web/pages/settings.payload-rules.test.tsx Tested: npm run repo:drift-check Not-tested: Manual browser interaction smoke on the Settings page in this clean PR worktree * Prevent payload-rules saves from violating review expectations Code review surfaced two operator-facing edge cases in the first payload-rules PR: successful rule parsing could still be committed before a later validation error, and visual edits could silently overwrite unsaved advanced JSON. This stages payload-rules until the request finishes validating and adds an explicit confirmation gate before visual actions discard unsynced advanced edits. Constraint: Keep the fix narrow to the reviewed payload-rules feature without refactoring unrelated runtime-settings atomicity behavior Rejected: Silently skipping draft resync while keeping visual edits active | would leave save semantics ambiguous when advanced JSON stays dirty Confidence: high Scope-risk: narrow Reversibility: clean Directive: If the settings endpoint ever moves toward full request atomicity, re-check this staged payload-rules write path against the broader strategy Tested: npm run typecheck Tested: npx vitest run --root . src/server/routes/api/settings.events.test.ts src/web/pages/settings.payload-rules.test.tsx Tested: npm run repo:drift-check Not-tested: Manual browser smoke of the confirmation dialog text |
||
|
|
2f774e204c |
Keep MySQL usage aggregation from crashing startup (#471)
The usage aggregation projector was written with SQLite/Postgres conflict builders, but Render can switch the runtime DB to MySQL from saved settings. That made the startup scheduler throw before the service stayed healthy. This change branches the projector's checkpoint and aggregate writes to MySQL-safe onDuplicateKeyUpdate calls while preserving the existing SQLite/Postgres onConflict behavior. A mocked MySQL regression test now omits the onConflict builders entirely so future regressions fail fast. Constraint: Drizzle conflict APIs are dialect-specific and the projector starts during boot Rejected: Disable the projector on MySQL | would keep admin analytics stale and hide the real incompatibility Confidence: high Scope-risk: narrow Reversibility: clean Directive: New usage-aggregation writes must branch on runtimeDbDialect before using conflict helpers Tested: npx vitest run --root . src/server/services/usageAggregationService.test.ts src/server/services/usageAggregationService.mysql.test.ts Tested: npm run typecheck:server Tested: npm run repo:drift-check Tested: npm run build:server Not-tested: Live MySQL projector pass against a deployed runtime database |
||
|
|
8cf78a5354 |
[codex] smooth route detail panel motion (#467)
* Keep route-detail motion smooth while restoring a more panel-like reveal feel The route page detail panel originally reused the shared collapse container, which looked lively but reintroduced layout-heavy motion inside the desktop route grid. This change keeps the non-layout presence shell, then tunes the panel animation itself so it reveals from the top with a softer, more trace-panel-like feel without falling back to grid row interpolation. Constraint: The desktop route detail panel sits inside a multi-column CSS grid and must avoid layout-driven collapse animation Rejected: Reuse anim-collapse exactly as ProxyLogs does | reopening grid-template-rows animation brought back jank on route expand/collapse Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve transform/clip-path-based motion here unless grid placement is redesigned; do not reintroduce layout collapse without profiling Tested: npm test -- src/web/pages/tokenRoutes.desktop-detail-panel.test.tsx src/web/pages/tokenRoutes.group-collapse.test.tsx src/web/pages/token-routes/RouteFilterBar.test.tsx Tested: npm run typecheck:web Tested: npm run typecheck:web:test Tested: npm run repo:drift-check Not-tested: manual GitHub review in production browser after PR creation * Keep route-detail motion PR lint-clean without changing behavior CodeRabbit correctly flagged the new keyframes for using from/to selector notation. This follow-up keeps the animation timing and properties the same while switching to percentage selectors so the stylesheet aligns with the configured keyframe selector rule. Constraint: Keep the route-detail panel motion unchanged while satisfying the style rule mentioned in PR review Rejected: Ignore the review comment | leaves a stylelint-style regression in the PR discussion unresolved Confidence: high Scope-risk: narrow Reversibility: clean Directive: When adding new keyframes in this stylesheet, prefer explicit percentage selectors to avoid repeating this lint issue Tested: npm test -- src/web/pages/tokenRoutes.desktop-detail-panel.test.tsx src/web/pages/tokenRoutes.group-collapse.test.tsx src/web/pages/token-routes/RouteFilterBar.test.tsx Tested: npm run typecheck:web Tested: npm run repo:drift-check Not-tested: remote Git transport from this machine still hangs, so branch update was handled separately from local git push * Respect reduced-motion and narrow layer promotion for route detail panel The new route detail panel motion path solved grid-driven jank, but the follow-up review correctly flagged two polish issues: the animation should honor reduced motion, and will-change should only stay enabled during active transitions. This keeps the smoother motion path while reducing persistent layer cost and giving reduced-motion users immediate state changes. Constraint: Must preserve the non-layout animation path that fixed dropped frames in the route grid Rejected: Restore anim-collapse behavior | reintroduces grid/layout-driven jank Confidence: high Scope-risk: narrow Directive: Keep desktop route detail motion on transform and clip-path rather than grid height animation unless the panel moves out of the card grid Tested: npm test -- src/web/pages/tokenRoutes.desktop-detail-panel.test.tsx src/web/pages/tokenRoutes.group-collapse.test.tsx src/web/pages/token-routes/RouteFilterBar.test.tsx Tested: npm run typecheck:web Tested: npm run typecheck:web:test Tested: npm run repo:drift-check Not-tested: Manual browser validation of prefers-reduced-motion on macOS * Honor reduced-motion semantics in route detail panel lifecycle The previous follow-up removed the always-on layer hint and added reduced-motion CSS, but the enter state still reused the long-lived open class and the desktop close path kept a fixed JS delay. This narrows will-change to a transient entering state, bypasses close delays for reduced-motion users, and locks the behavior with a regression test. Constraint: Must preserve the non-layout detail-panel motion path that fixed grid jank Rejected: Keep reduced-motion as CSS-only | JS close timer still delayed unmount and active-state cleanup Rejected: Drop the close delay globally | would remove the intended close animation for standard-motion users Confidence: high Scope-risk: narrow Directive: If the desktop detail panel motion changes again, keep motion-state CSS and JS timers aligned for prefers-reduced-motion users Tested: npm test -- src/web/pages/tokenRoutes.desktop-detail-panel.test.tsx src/web/pages/tokenRoutes.group-collapse.test.tsx src/web/pages/token-routes/RouteFilterBar.test.tsx Tested: npm run typecheck:web Tested: npm run typecheck:web:test Tested: npm run repo:drift-check Not-tested: Manual browser verification of prefers-reduced-motion on macOS |
||
|
|
c6a28c71c4 |
[codex] improve LobeHub brand detection coverage (#464)
* Recognize more LobeHub-backed model brands so marketplace filters stop collapsing into other Metapi was leaving many models under the uncategorized bucket even though the current LobeHub icon set already contains matching provider or vendor brands. This change moves brand detection into one shared registry, expands the rules with the user-reported gaps that have real upstream icon coverage, and makes server-side brand blocking reuse the same classification result as the web UI. Constraint: Existing workspace has unrelated in-progress edits, so this commit stages only the brand-classification slice Constraint: Brand matching must stay consistent between marketplace display and server-side blocked-brand filtering Rejected: Add more ad hoc rules separately in web and server files | would keep the drift bug alive Rejected: Blindly import every LobeHub slug as a model brand | would pollute filters with tool and app brands Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep new brand additions in src/server/shared/modelBrand.ts and let web/server consume that single source of truth Tested: npm test -- src/web/components/BrandIcon.test.ts src/server/services/brandMatcher.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx Tested: npm run typecheck Tested: npm run repo:drift-check Not-tested: Live browser verification against the user's current marketplace dataset after deployment * Preserve provider brand blocking without changing display-brand priority The first pass unified brand detection but server-side blocked-brand checks started relying on the single display brand. Mixed model paths such as `deepinfra/meta-llama/...` and `azureai/gpt-4o` still need provider markers to match global blocked brands even while the UI continues to show the preferred vendor label. Constraint: Marketplace display should keep the current preferred vendor-first brand label Constraint: Server-side blocked-brand matching must still recognize provider and vendor markers on the same model id Rejected: Reorder display-brand priority to make provider blocks pass | would regress the marketplace labels the PR was improving Rejected: Reintroduce a separate server-only matcher | would recreate the web/server drift this PR removed Confidence: high Scope-risk: narrow Reversibility: clean Directive: Use getMatchingBrandNames for blocking-style checks and reserve getBrand for single-label display surfaces Tested: npm test -- src/server/shared/modelBrand.test.ts src/server/services/brandMatcher.test.ts src/web/components/BrandIcon.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx Tested: npm run typecheck Tested: npm run repo:drift-check Not-tested: Live GitHub review-thread auto-resolution behavior after push * Honor legacy blocked brand casing when canonicalizing global brand filters The shared brand matcher now supports multi-match provider blocking, but the blocked-brand rule parser still required exact display-case brand names. That meant imported or legacy settings like `openai` or `aws bedrock` were silently ignored even though they should map to known brands. Constraint: Existing saved settings may contain lower-case or whitespace-variant brand names from imports or older data Constraint: The server should keep emitting canonical display names after normalizing user-provided blocked brand entries Rejected: Assume the settings UI always writes canonical brand strings | does not cover imported or hand-edited configuration Rejected: Normalize only at the settings route | would still leave hydrated legacy config values ineffective in modelService Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep blocked-brand parsing tolerant of case and spacing drift, but always return canonical brand names for downstream use Tested: npm test -- src/server/services/brandMatcher.test.ts src/server/shared/modelBrand.test.ts src/web/components/BrandIcon.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx Tested: npm run typecheck Tested: npm run repo:drift-check Not-tested: Manual settings UI round-trip with legacy lowercase globalBlockedBrands payloads |
||
|
|
baead855dd |
Make admin reads snapshot-first for faster ops pages (#457)
* Make admin reads snapshot-first so heavy pages stay responsive This introduces a lightweight snapshot/cache layer for the busiest admin reads, splits dashboard and proxy-log loading into smaller independent surfaces, and moves accounts/site/dashboard snapshots toward service-owned read paths. The UI now loads dashboard summary, dashboard insights, site stats, accounts, and proxy-log metadata as separate progressive reads while keeping existing feature coverage intact. Constraint: Must keep the full admin feature set and core metrics intact Constraint: Interactive admin flows should trend toward <=3s without relying on OpenResty-only band-aids Rejected: Delete heavy pages or reduce statistics depth | user explicitly requires unchanged functionality Rejected: Keep one giant proxy-log/dashboard response | preserves current timeout-prone read shape Confidence: medium Scope-risk: moderate Directive: Preserve old endpoints during the migration and keep new snapshot/query-v2 surfaces as the preferred frontend path Tested: npm run typecheck Tested: npx vitest run --root . src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/routes/api/stats.proxy-logs.test.ts src/server/routes/api/stats.siteStatus.test.ts src/server/routes/api/accounts.todayRewardFallback.test.ts Tested: npm run build Tested: npm run repo:drift-check Not-tested: Live cita/cita1 latency measurements against the production dataset * Keep snapshot services lean after the admin read-path rollout The snapshot-first rollout now has fresh production evidence on cita1, so this follow-up trims two no-op patterns without changing behavior: a single-element Promise.all and a catch-then-rethrow refresh chain. Keeping the service layer lean reduces noise before final Ralph sign-off and redeploy verification. Constraint: Keep deployed behavior unchanged while satisfying the mandatory deslop pass Rejected: Wider refactor across route files | would broaden the verified surface right before production comparison closeout Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep snapshot services focused on cache/read orchestration; avoid reintroducing decorative async wrappers Tested: npm run typecheck; npm run build; targeted vitest snapshot/proxy-log/account suites; npm run repo:drift-check Not-tested: Public Cloudflare path, which still appears to hit a different origin than cita1 * Keep admin snapshots warm without introducing Redis This moves the new admin read path beyond process-local caching by persisting snapshot payloads in a dedicated admin_snapshots table and warming them in the background. It also migrates remaining lightweight internal callers away from the heaviest legacy reads and marks legacy endpoints as deprecated instead of deleting them abruptly. Constraint: User explicitly rejected adding Redis for admin snapshot acceleration Rejected: Redis-backed shared cache | adds a forbidden runtime dependency Rejected: Delete legacy endpoints immediately | still breaks tests, docs, and compatibility callers Confidence: high Scope-risk: moderate Directive: Remove legacy admin endpoints only after internal callers, docs, and compatibility windows are cleared Tested: npm run typecheck Tested: npm run build Tested: npx vitest run --root . src/server/services/adminSnapshotStore.test.ts src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/services/startupInfo.test.ts Tested: npm run repo:drift-check Not-tested: cita1 staging redeploy on this follow-up commit * Collapse admin reads onto the canonical API paths This removes the parallel v2 read surface and routes the snapshot-first implementation back through the original admin API names. The frontend now uses the canonical paths again while the backend keeps the newer snapshot, persistence, and warm-refresh machinery behind those routes. Along the way it also fixes the main review findings around cache coalescing, active-site scope, atomic snapshot writes, and auth-header handling. Constraint: User requested no Redis and no long-lived duplicate admin read endpoints Rejected: Keep both legacy and v2 endpoints indefinitely | doubles maintenance and confuses the canonical contract Rejected: Delete old names without remapping callers | would create avoidable frontend and tooling churn Confidence: high Scope-risk: moderate Directive: Treat /api/stats/dashboard, /api/accounts, /api/stats/proxy-logs, and the site stats routes as the canonical admin read contract unless a future breaking-change plan says otherwise Tested: npm run typecheck Tested: npm run build Tested: npx vitest run --root . src/server/services/adminSnapshotStore.test.ts src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/routes/api/stats.proxy-logs.test.ts src/server/services/startupInfo.test.ts Tested: npm run repo:drift-check Not-tested: cita1 staging redeploy on this canonical-route follow-up commit * Keep canonical admin analytics fast without raw log scans This lands the usage-aggregate path as the single implementation behind the canonical admin routes, adds the aggregate schema/migration artifacts, and reconnects dashboard/site stats warming to the new service so the PR no longer sits in a half-projector state. It also updates the cache and aggregate tests to reflect the real runtime behavior and validates the current branch on cita1 staging, which showed the app-side snapshot path is fast while the remaining 1.5s staging slowness lives on the NodePort path rather than inside the aggregate queries themselves. Constraint: Must preserve the canonical old-path admin API contract while moving reads onto aggregate-backed snapshots Constraint: Must not add Redis or a parallel second analytics implementation Rejected: Keep usageAggregationProjectorService as a separate path | would preserve duplicate ownership and keep type wiring split Rejected: Judge staging performance only from NodePort timings | hid that pod-local snapshot reads were already fast Confidence: medium Scope-risk: moderate Directive: If dashboard or insights feels slow again on staging, compare NodePort and pod-local timings before changing aggregate queries Tested: npm run typecheck; npx vitest run --root . src/server/services/adminSnapshotStore.test.ts src/server/services/usageAggregationService.test.ts src/server/services/snapshotCacheService.test.ts src/server/routes/api/accounts.snapshot-v2.test.ts src/server/routes/api/stats.snapshot-v2.test.ts src/server/routes/api/stats.proxy-logs.test.ts src/server/services/startupInfo.test.ts; npm run build; npm run repo:drift-check; cita1 staging deploy plus canonical-route curl benchmarks Not-tested: cita1 real ingress/OpenResty path; multi-replica projector concurrency * Prevent admin aggregate drift under concurrent warmers This follow-up hardens the snapshot-first admin analytics path by adding a persisted projector lease, exact 24-hour dashboard counting, and regression coverage for lease contention and time-window behavior. The goal is to keep the canonical admin routes correct when multiple workers are alive and to avoid quietly overstating proxy24h by reading hour buckets as if they were an exact sliding window. Constraint: Projector coordination must work through the existing checkpoint table without adding Redis or a second background system Constraint: Schema artifacts must stay additive under the repo's generated bootstrap/upgrade pipeline Rejected: Remove the left-prefix day/hour indexes in this slice | schema:contract rejects non-additive index removals, so that cleanup needs a broader migration strategy Confidence: high Scope-risk: moderate Directive: Keep projector claims DB-backed; do not regress to process-local inFlight-only dedupe for aggregate writes Tested: npm run typecheck; npx vitest run --root . src/server/services/usageAggregationService.test.ts src/server/routes/api/stats.snapshot-v2.test.ts; npm run build; npm run repo:drift-check Not-tested: Multi-host live contention beyond synthetic lease test; resolving CodeRabbit index-nit without additive-schema support * Keep CI aligned with canonical admin snapshots The admin snapshot cutover left a mixed test surface: MySQL schema artifacts still classified admin_snapshots.snapshot_key as JSON, canonical /api/accounts callers were asserted as arrays, and a few proxy tests mocked routeRefreshWorkflow too narrowly, which leaked missing exports into later OAuth runs. This commit narrows the schema metadata heuristic, updates the checked-in schema artifacts and their regression tests, adds lightweight web test compat helpers for canonical snapshot APIs, and preserves actual routeRefreshWorkflow exports so full-suite workers no longer poison unrelated tests. OAuth/account token suites also reset DATA_DIR-backed modules safely to avoid stale singleton config. Constraint: checked-in schema artifacts drive cross-dialect CI parity checks Constraint: vitest module mocks can leak across files in the same worker when exports are omitted Rejected: rerun schema:generate only | additive guard rejects the logical-type correction for snapshot_key Rejected: keep per-test ad hoc snapshot mocks | repeated breakage across pages needed one compat helper Confidence: high Scope-risk: moderate Directive: when a test uses vi.resetModules with mutable config or DATA_DIR state, re-import those modules after the reset instead of mutating a stale top-level singleton Tested: npm test Tested: npm run typecheck Tested: npm run build Tested: npm run repo:drift-check Tested: npm run test:schema:parity Not-tested: live MySQL schema parity against a local MySQL instance * Keep CodeQL from re-flagging already-limited routes GitHub Advanced Security still marked three admin routes as missing rate limits because the repository uses a custom Fastify preHandler wrapper instead of one of the middleware packages modeled by the CodeQL query. The routes are already throttled in production, so this change adds narrow in-source suppressions on the three affected handlers to record that the check is a false positive instead of a real missing guard. Constraint: repo policy forbids adding new dependencies just to satisfy a static analyzer Constraint: the custom createRateLimitGuard preHandler is runtime-correct but not modeled by CodeQL's missing-rate-limiting query Rejected: add fastify-rate-limit | would introduce a new dependency and duplicate existing guard behavior Rejected: dismiss alerts only in GitHub UI | leaves the false-positive rationale detached from the source line that keeps re-triggering the alert Confidence: medium Scope-risk: narrow Directive: if these routes are ever converted away from createRateLimitGuard, remove or revisit these suppressions rather than assuming they remain safe forever Tested: npm run typecheck Tested: npm run repo:drift-check Not-tested: full npm test rerun after comment-only suppression change * Use legacy CodeQL suppression syntax for custom rate guards The modern source suppression comment did not affect GitHub Advanced Security's missing-rate-limiting check on these Fastify handlers. Switch the three known false-positive locations to the legacy LGTM suppression syntax, keeping the custom preHandler throttling in place while matching the syntax that CodeQL still honors for in-source suppressions. Constraint: createRateLimitGuard remains the runtime source of truth for throttling in this repo Constraint: GitHub's missing-rate-limiting query does not model the repo's custom Fastify preHandler wrapper Rejected: dismiss the alerts in the GitHub UI | the rationale should stay attached to the source line that keeps re-triggering the alert Rejected: add a recognized rate-limit dependency | repo rules disallow a new dependency for analyzer appeasement alone Confidence: medium Scope-risk: narrow Directive: if GitHub eventually honors the newer codeql[] syntax here, remove whichever suppression form becomes redundant so the file keeps one clear rationale Tested: Not run locally (comment-only suppression syntax change) Not-tested: GitHub CodeQL rerun after switching to LGTM suppression syntax * Keep admin routes clean after CodeQL false-positive triage The repository's custom createRateLimitGuard preHandlers are the actual runtime throttles for these routes. Since GitHub Advanced Security still did not honor the attempted in-source suppressions, remove the temporary comments and keep the source focused on runtime behavior while the false-positive alerts are tracked operationally in GitHub. Constraint: the custom Fastify preHandler remains the only real throttling mechanism in this repo Rejected: leave non-functional suppression comments in source | they imply enforcement that GitHub did not actually honor Confidence: high Scope-risk: narrow Directive: if CodeQL adds custom Fastify preHandler modeling later, prefer removing any alert dismissals over reintroducing comment noise here Tested: Not run locally (comment-only cleanup) Not-tested: GitHub checks after alert dismissal |
||
|
|
6cca74b039 |
Recognize more LobeHub-backed model brands so marketplace filters stop collapsing into other
Metapi was leaving many models under the uncategorized bucket even though the current LobeHub icon set already contains matching provider or vendor brands. This change moves brand detection into one shared registry, expands the rules with the user-reported gaps that have real upstream icon coverage, and makes server-side brand blocking reuse the same classification result as the web UI. Constraint: Existing workspace has unrelated in-progress edits, so this commit stages only the brand-classification slice Constraint: Brand matching must stay consistent between marketplace display and server-side blocked-brand filtering Rejected: Add more ad hoc rules separately in web and server files | would keep the drift bug alive Rejected: Blindly import every LobeHub slug as a model brand | would pollute filters with tool and app brands Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep new brand additions in src/server/shared/modelBrand.ts and let web/server consume that single source of truth Tested: npm test -- src/web/components/BrandIcon.test.ts src/server/services/brandMatcher.test.ts src/web/pages/Models.marketplace-text.test.tsx src/web/components/BrandIcon.architecture.test.ts src/web/components/BrandIcon.render.test.tsx Tested: npm run typecheck Tested: npm run repo:drift-check Not-tested: Live browser verification against the user's current marketplace dataset after deployment |