Skip to content

#3071 诊断与修复:plugin-audit#test 在托管 runner 上静默失败#3073

Merged
os-zhuang merged 15 commits into
mainfrom
claude/objectql-protocol-layering-s2sn67
Jul 16, 2026
Merged

#3071 诊断与修复:plugin-audit#test 在托管 runner 上静默失败#3073
os-zhuang merged 15 commits into
mainfrom
claude/objectql-protocol-layering-s2sn67

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

处理 #3071:plugin-audit#test 仅在 GitHub 托管 runner 上失败(三次确定性复现,始于 main 4f8c2d1),vitest 零输出 exit 1;本地在 Node 20/22、UTC、CI 环境变量、精确 CI 命令下全部通过。main 的 Test Core 自 4f8c2d1 起处于"假绿"(路径过滤跳过)状态,本问题会挡住所有触碰代码的 PR。

当前阶段:诊断轮。 ci.yml 中加入两个临时步骤(标记 TEMPORARY,合并前移除):

  1. turbo 之前:隔离、verbose、无分组地直接跑 plugin-audit 的 vitest(新机器基线)——真实输出不再可能被 GH 日志管道在洪峰下丢弃;timeout -s QUIT 让 Node 在挂起时转储各线程堆栈;
  2. turbo 之后(always()):dmesg 抓内核 OOM 痕迹 + 在跑完整个任务图的机器上二次隔离重跑。

拿到真实失败输出后,本 PR 将替换为根因修复并移除诊断步骤。

🤖 Generated with Claude Code

https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu


Generated by Claude Code

claude added 15 commits July 16, 2026 08:26
…pter on raw node:http (ADR-0076 D11/OQ#10, #2462)

Multi-adapter was designed but unproven: only the Hono adapter existed, and
ADR-0076 D11 flagged 'the normalized context shows Hono-isms' as a caveat
blocking the transport decomposition. This adds the validation:

- New @objectstack/plugin-node-server: a thin IHttpServer implementation on
  raw node:http with ZERO dependencies beyond @objectstack/core — :param +
  trailing-* routing (registration-order first-match, same as the primary
  adapter), eager JSON/urlencoded body parse with lazy rawBody() for binary,
  SSE via native res.write/end, 404/405-with-Allow semantics, EADDRINUSE
  retry, graceful drain on close. Deliberately no getRawApp()/mount().
- Cross-adapter conformance suite: boots the dispatcher bridge AND the REST
  route generator (with ObjectQL + memory driver) on BOTH adapters over real
  sockets — /data CRUD roundtrip, /meta reads, /ready, /health, discovery,
  :param routing, 404/405 parity, plus a probe-for-probe response-shape
  parity matrix between the two adapters. 40 assertions, all green.

Findings recorded in ADR-0076 (OQ#9/OQ#10/OQ#11 resolution notes):
- The port has NO hard Hono-isms. The Host-header backfill in the Hono
  adapter is a Fetch-API artifact local to that adapter, not a port leak.
- All remaining Hono coupling is confined to the feature-detected
  getRawApp() escape hatch (metadata HMR, cloud-connection routes,
  static/SPA + CORS + Server-Timing) which degrades gracefully.
- Follow-up for the D11 window: codify res.write/res.end (SSE) and
  getPort() — extensions consumers already rely on — plus 404/405
  semantics into the IHttpServer contract.
- OQ#9 audit verdict (delineate, don't merge; only discovery + packages
  are genuinely double-mounted) recorded in the ADR open-questions list.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
…ion (CodeQL)

CodeQL flagged remote property injection: query-param keys come straight
from the request URL, so building the map on a plain object literal let
'?__proto__=…' write through the prototype chain. Use null-prototype
objects for query and params and drop the dangerous keys
(__proto__/constructor/prototype) outright; regression test pins that
'?__proto__=polluted' is dropped and Object.prototype stays clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
…deQL flags

The blacklist guard added in the previous commit was not recognized as a
sanitizer by CodeQL's js/remote-property-injection rule — the sink is the
computed write itself (obj[userKey] = …). Build query and params via
Object.fromEntries (own data properties only, no prototype-chain walk) so
the sink no longer exists; the __proto__/constructor/prototype drop stays
as defense in depth. Regression test unchanged and green (41/41).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
… gate — packages/qa/http-conformance

Maintainer review: the node:http adapter is a validation instrument, not a
product server, so it must not ship as a publishable plugin- package.
Reposition it accordingly:

- Move packages/plugins/plugin-node-server → packages/qa/http-conformance;
  rename @objectstack/plugin-node-server → @objectstack/http-conformance,
  private: true, test-only (no build/publish), matching the existing
  verification-gate packages (dogfood, downstream-contract).
- packages/qa/ becomes the unified home for non-published verification
  gates (new pnpm-workspace glob); migrating dogfood/downstream-contract
  there is proposed as a follow-up.
- Drop the changeset + fixed-group entry (private packages are not
  versioned); update the ADR-0076 OQ#10 note to the new name.

Behavior unchanged: same adapter, same 41-assertion cross-adapter
conformance suite, all green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
… (unified verification-gate home)

Completes the packages/qa/ consolidation started with http-conformance:
all three non-published verification gates (dogfood regression gate,
downstream-contract compatibility gate, http-conformance port gate) now
live under one directory.

Mechanical path migration — no behavior change:
- git mv packages/{dogfood,downstream-contract} → packages/qa/
- rewrite every 'packages/dogfood' / 'packages/downstream-contract'
  breadcrumb: spec liveness proof registry + JSON ledgers,
  spec-liveness-check.yml path trigger, eslint ignore, docs/ADRs,
  source comments
- bump the repo-root traversal one level in the four dogfood conformance
  tests that resolve REPO_ROOT from __dirname

Verified from the new locations: dogfood 273 passed / 3 skipped,
downstream-contract typecheck + 14 tests, spec check:liveness resolves
all bound proofs, http-conformance 41/41.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
…col-layering-s2sn67

# Conflicts:
#	packages/qa/dogfood/test/owner-anchor-and-bulk-writes.dogfood.test.ts
…echeck job + correct stale ADR-0076 D12 status

Two follow-ups after merging latest main:

- lint.yml: the example-app typecheck step built only ./packages/* (direct
  children). The connector packages the showcase imports were built purely
  by accident — through dogfood's dependency chain — which broke when
  dogfood moved to packages/qa/. Request the examples' dependency closure
  explicitly (--filter='./examples/*^...') so the step no longer depends
  on which package happens to live at the top level.
- ADR-0076: the round-2 status verification merged from main (#3061) was
  read against a pre-#3028 snapshot — svcAvailable no longer hardcodes
  'available'; the D12 framework side shipped in #3028. Correct the status
  line and note OQ#9/OQ#10 resolution (#3037).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
…itigation)

Test Core started failing deterministically on the hosted runner —
plugin-audit#test dies with ZERO vitest output (kernel OOM-kill
signature) while passing locally on Node 20 and 22 — first on main
@4f8c2d1, then twice on this PR (initial run + job re-run). Onset
correlates with the task graph growing past ~100 tasks (connector
packages + qa gates): turbo's default concurrency (10) schedules that
many vitest workers + tsup DTS builds onto a 4-vCPU runner and peak
memory tips over.

Cap test-step concurrency at 4 (PR affected-tests + push full-run).
CPU-bound workload, so wall-clock cost is minimal; peak memory becomes
bounded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
…col-layering-s2sn67

# Conflicts:
#	packages/qa/dogfood/test/showcase-declarative-mcp.dogfood.test.ts
#	pnpm-lock.yaml
…dogfood test + regen lockfile after merge

showcase-declarative-mcp.dogfood.test.ts landed on main (#3062) against
the old packages/dogfood location; after the packages/qa migration its
'../../../examples/app-showcase' URL resolved inside packages/. One more
level, same as the other conformance tests. Lockfile regenerated after
taking main's side in the merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
…+ dmesg OOM probe

plugin-audit#test dies on the hosted runner with zero captured output
(3x deterministic since main@4f8c2d1) while passing locally under Node
20/22 with the exact CI command. Bracket the turbo test step with an
isolated, verbose, ungrouped vitest run (before: fresh machine; after:
post-graph machine + kernel OOM traces) so the real failure output cannot
be lost to the GH log pipeline. SIGQUIT-on-timeout dumps Node thread
stacks if it hangs. To be REMOVED once #3071's root cause is fixed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 16, 2026 3:19pm

Request Review

@os-zhuang
os-zhuang marked this pull request as ready for review July 16, 2026 15:23
@os-zhuang
os-zhuang merged commit 5725b52 into main Jul 16, 2026
15 checks passed
@os-zhuang
os-zhuang deleted the claude/objectql-protocol-layering-s2sn67 branch July 16, 2026 15:23
os-zhuang pushed a commit that referenced this pull request Jul 16, 2026
… depend on built dist (#3071, #3060)

Root cause of #3071, reproduced locally on a fresh unbuilt worktree:
plugin-audit and plugin-dev were the only test suites with NO
vitest.config — vitest resolved their workspace deps through package.json
exports, i.e. dist/. Whether those tests even LOADED therefore depended
on turbo build ordering and cache-restore integrity on the runner:
'Failed to resolve entry for package @objectstack/core', surfacing as the
deterministic zero-output Test Core failure (the output itself was lost
to the GH log pipeline under burst — proven by the #3073 isolated run).

- Add vitest.config.ts with src aliases to both packages (the same
  convention plugin-hono-server et al. already use); verified green on a
  completely unbuilt tree — the exact CI condition.
- plugin-dev (#3060): mock the ~10 heavy dynamic imports in the
  'missing deps' test as genuinely missing (ERR_MODULE_NOT_FOUND
  factories) — the degradation branch is exercised for real and the
  full-parallel 15s timeout flake disappears; drop the inflated timeout.
- Remove ALL TEMPORARY #3071 diagnostic steps from ci.yml (rounds 1+2);
  keep the --concurrency=4 resource cap with a trimmed comment (the OOM
  attribution in it was wrong — the real cause was unresolvable dist).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants