Skip to content

feat: deliver Sub2API 0.2.7 and independently signed plugins - #191

Merged
HTExplicit merged 171 commits into
mainfrom
feat/v027-plugin-architecture
Sep 22, 2026
Merged

HTExplicit merged 171 commits into
mainfrom
feat/v027-plugin-architecture

Conversation

@HTExplicit

@HTExplicit HTExplicit commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Delivery scope

  • Integrate the exact official Sub2API v0.2.7 baseline while retaining downstream OAuth cost anchoring, quota/rate-limit display, ordinary/Spark isolation and explicit connection-test reasoning effort.
  • Deliver seven independently packaged plugin domains and their interfaces through the public SDK/UI Bridge and named host operations. Preserve capability/account scope, configuration CAS, execution generations and durable task ownership.
  • Deliver signed single-plugin updates with target-process replacement, immutable package identity, pinned-version persistence and explicit return to the bundled version.
  • Preserve confirmed account semantics: ordinary OpenAI+Laxa stays ordinary OpenAI; unchanged edit fields remain unchanged, explicit auto is stored, finite explicit clears remove only registered keys, and copying Cindy does not invent a protocol default.

Validation and release boundary

Existing successful checks are reused only for matching source digests. Remaining registered failures are handled with exact targeted tests; all normal required PR checks remain mandatory. No real model requests were sent. Mocked-browser evidence is not represented as production authorization or model-quality validation.

The local closeout passed the exact catalog checks (3), WebSocket/control-frame checks (3), cache CAS check (1), all 9 previously recorded service failures, and the focused frontend controls. Necessary frontend fixes remove duplicate detail polling and capture the complete account selection before a new plugin dialog renders. Existing account-page operation history remains the daily entry; retired header/sidebar task centers are not reintroduced. Focused formatting/lint and coverage-inventory consistency passed. No valid assertion or required CI job was removed. CI remains enabled for every branch push and PR; release-tag pushes no longer duplicate those business tests. Linux CI additionally identified a Go OS-filename collision: the quota source and test were renamed from _windows.go/_windows_test.go to _window_state.go/_window_state_test.go, with both file digests unchanged and the Linux host build verified.

The coverage inventory retains real pending records. Completing all historical root-tool reviews is no longer a release prerequisite. Historical diagnostics, old full acceptance, additional telemetry and capacity WIP remain local and are not shipped, installed or executed. The completed external VPN six-exit/Japan-retirement baseline is untouched by this change.

After merge, v0.2.7-codexrip.1 will be built from the final admitted source using the existing codexrip-plugins-v1 publisher. The host image reuses the exact seven signed packages. Deployment uses the fixed reviewed maintenance sets, immutable image digest, natural drain and runtime=preserve, rebuilding only Sub2API. CPA stays stopped; image features and retired public model management remain disabled; existing data, mappings, resources and network configuration are preserved.

HuntercodeT and others added 30 commits September 15, 2026 16:50
Paused (schedulable=false) active accounts were excluded from the
background token refresh candidates, so their stored access_token
silently expired. The admin usage-window quota probe uses the stored
token verbatim (no token provider / no refresh), so the probe then gets
HTTP 401 UNAUTHENTICATED and the dashboard reports a false "needs
re-auth" for a perfectly healthy account, while Test Connection and live
traffic (which refresh on demand via the token provider) keep working.

Pause is not permanent rejection: error accounts are already excluded by
the status = 'active' filter, and accounts whose refresh genuinely fails
are rate-limited by the retry-cooldown exclusion (10-minute retry-
exhausted cooldown). Refresh success only persists credentials and never
touches schedulable, so a paused account cannot be silently un-paused.

Drop the schedulable filter and update the SQL-filter test, the
integration pagination test, and the service-level candidate fake.
GET /api/v1/admin/groups/usage-summary 在有一定数据量的库上会退化成
usage_logs 全表扫。根因是 getAllGroupUsageSummaryFromRollups 里,tail CTE
的 created_at 下界 state.tail_start 由同一条 SQL 的 state CTE 算出、再用
CROSS JOIN 交给 tail:这个值对 planner 来说要到运行期才知道,既进不了
index cond,也估不准选择性,于是只能顺序扫全表再逐行过滤。

生产实测(1721 万行 usage_logs / PostgreSQL 17):

    Nested Loop  (actual time=28161..48334 rows=34788)
      Join Filter: (ul.created_at >= state_1.tail_start)
      Rows Removed by Join Filter: 17178082
      ->  Seq Scan on usage_logs  (actual time=0.030..47567 rows=17212870)
          Buffers: shared hit=12863 read=951875
    Execution Time: 48720 ms

改成先读一次水位行、在 Go 侧算出 tail_start / closed_before / retained
日期,再把它们当查询参数传进来。同一套数据上:

    Index Scan using idx_usage_logs_created_at on usage_logs
      Index Cond: (created_at >= $7)
    Execution Time: 34 ms

水位有效性的判定(恰好一行、时区名与配置一致、水位不在未来)和无效时
退化成从 epoch 全量重算的行为,与原先 SQL 里 state_values / CASE WHEN
valid 的分支逐条对应,结果口径不变。

另外读取水位的语句不加锁,不参与 Wei-Shaw#6976 那条 FOR UPDATE / FOR KEY SHARE
的阻塞链。
DeepSeek native Responses rejects Codex view_image results when function_call_output.output contains input_image parts. Move media into a following user message and keep the tool output as a string so call_id pairing remains valid.
Security Scan / backend-security 自 2026-09-16 起在所有 PR 上失败,govulncheck 对
google.golang.org/grpc v1.82.1 报:
- GO-2026-6443 Server panic via missing authority or Host headers(修复于 v1.83.2)
- GO-2026-6348 Heap Memory Exhaustion via HTTP/2 DATA Frame Fragmentation(修复于 v1.83.1)
调用链在 pkg/pluginapi/v1/runtime.go 与 internal/service/plugin_runtime.go。

go get google.golang.org/grpc@v1.83.2 && go mod tidy。最小版本选择连带抬升了
golang.org/x/{crypto,mod,net,sync,term,sys,text,tools}、genproto/googleapis/rpc 与
go.opentelemetry.io/otel* 的间接依赖,均为补丁级别。
…ump-number

fix(pagination): handle numeric jump input
Codex and others added 19 commits September 22, 2026 01:17
…over)

Codex's uncommitted account.edit batch, committed as-is after validation by the
coordinator: backend builds and vets clean; unit tests for handler/admin, dto,
repository, extensionapi and pluginapi pass; the six new/changed frontend specs
pass (152 cases) and vue-tsc is clean. Two test failures in service and routes
predate this change (they fail at 9f423dd too) and are fixed separately.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
cd8c18b moved the probe policy check in Resume after the repository read,
so a disabled or unavailable Cindy probe policy still hit persistence and
TestCindyProbeDisabledPolicyDoesNotClaimJobsOrDeleteHistory panicked on the
nil repository. Check the policy first again; scoped jobs still re-check it
inside the rebound origin context.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Root cause: e36c115 (account edit contract) made BulkEditAccountModal
route bulk updates through accountAPIForView() from @/api/admin/accounts.
The spec's vi.mock factory for that module only exported
getAntigravityDefaultModelMapping, so every submit threw
'No "accountAPIForView" export is defined on the mock' (36 failures).

Fix: add a pass-through stub (returns the core API, mirroring the real
helper's behaviour when no view is captured). Product code unchanged.
Evidence: vitest run BulkEditAccountModal.spec.ts -> 58/58 pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
TestGatewayRoutesPinnedModelsDispatchesOrdinaryAndCodexRequests expected
"context_capacity_source":"official" for gpt-5.5 but got "default" /
"no_verified_capacity". Root cause: commit 7693615 moved the official
model context capacity catalog into the signed model-policy plugin;
LookupOfficialModelContextCapacity now goes through the process-level
extension catalog (processExtensionCatalog), which is nil unless the
plugin manager or a test fixture installs it. That commit added
plugin_contract_fixture_test.go (init: testextensions.Install()) to
internal/handler, handler/admin and repository but not to server/routes,
so this fixture had no catalog. Production is unaffected: the catalog
is composed by ProvidePluginManager.

Test-only change: install the shared testextensions fixture for this
test and restore the nil provider on cleanup, matching the sibling
packages. No production code touched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Root cause: c3b17da (Cindy management UI) wrapped the group audit
button in <ExtensionSurface name="cindy-group-audit"> and mounted the
real CindyGroupAuditDialog (-> ExtensionModal -> useRetainedContribution)
inside GroupsView. Both read the usePluginExtensions Pinia store, and
neither GroupsView spec installs Pinia, so every mount threw
'getActivePinia() was called but there was no active Pinia' (21 failures).

Fix: reuse the existing test pattern from AccountBulkActionsBar /
AccountDetailsDrawer specs - vi.mock ExtensionSurface.vue with a slot
passthrough so the audit button still renders for the column-settings
audit test - and stub CindyGroupAuditDialog in the duplicate spec the
same way the column-settings spec already does. Product code unchanged.
Evidence: vitest run GroupsView.duplicate.spec.ts (12/12) and
GroupsView.columnSettings.spec.ts (9/9) pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…w spec

Root cause: cd8c18b (scoped account views) intentionally removed the
hard-coded Cindy recover button and its 'recover-cindy-balance' event
from AccountActionMenu.vue; Cindy affordances are plugin contributions in
the generic account.actions slot now and the cindy_balance_insufficient
marker only feeds account-view predicates (components/plugins/accountView.ts)
and the status badge. No non-test code references the old entry.

The spec still expected the button, failed before its wrapper.unmount(),
and its teleported menu leaked into document.body, which is why the four
following not.toContain / button-lookup tests also failed (5 failures).

Fix: replace the expectation with the single inverse assertion that the
core menu no longer renders the Cindy entry for a marked account.
Product code unchanged. Evidence: vitest run
AccountActionMenu.spark_shadow.spec.ts -> 13/13 pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@HTExplicit
HTExplicit merged commit 300bd6d into main Sep 22, 2026
16 checks passed
@HTExplicit
HTExplicit deleted the feat/v027-plugin-architecture branch September 22, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.