Skip to content

ADR-0076 D11 前置验证:HTTP 端口一致性门(packages/qa/http-conformance)+ OQ#9/10 结论 (#2462)#3037

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

ADR-0076 D11 前置验证:HTTP 端口一致性门(packages/qa/http-conformance)+ OQ#9/10 结论 (#2462)#3037
os-zhuang merged 13 commits into
mainfrom
claude/objectql-protocol-layering-s2sn67

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

继续 #2462:落地 D11 的两个前置项(均为 framework 单仓库、不动现有行为),为跨仓库窗口的 transport 拆解扫清前提。

OQ#10 — 多适配器验证(本 PR 的代码部分)

ADR-0076 D11 的警告是"multi-adapter 未经验证,normalized context 有 Hono 痕迹"。本 PR 给出验证:

  • 新私有 QA 门 @objectstack/http-conformance(packages/qa/http-conformance,private: true 不发布):在裸 node:http 上实现 IHttpServer 端口的参照实现,除 @objectstack/core 外零依赖——没有框架替端口补路由/补解析,消费方一旦依赖任何 Hono 特有能力,套件立即失败。定位是验证仪器,不是产品服务器(生产继续用 plugin-hono-server;面向用户的 Express/Workers 适配器留到窗口期作为产品决策单独做,届时插进本套件的 ADAPTERS 数组即可免费获得同套验证)。
  • 跨适配器一致性测试套件:在参照实现与 plugin-hono-server 上分别拉起真实栈(dispatcher 桥 + REST 生成器 + ObjectQL + 内存驱动,真实 socket),断言行为一致——/data CRUD 全流程、/meta 读取、/ready /health、discovery、:param 路由、404/405+Allow、SSE,外加逐探针的响应形状对比矩阵。41 条断言全绿。

结论:端口没有硬性 Hono 依赖。 Hono 适配器里的 Host 头回填是 Fetch API 的产物、属适配器本地行为而非端口泄漏;剩余 Hono 耦合全部锁定在 getRawApp() 逃生舱(metadata HMR、cloud-connection 路由、static/SPA + CORS + Server-Timing),消费方均做了特性探测、可优雅降级。窗口期跟进项:把消费方已依赖的两个软扩展(res.write/endgetPort())和 404/405 语义正式写进 IHttpServer 契约。

目录组织:packages/qa/ 作为不发布验证门的统一位置(新 workspace glob);现有同类包 packages/dogfoodpackages/downstream-contract 建议后续迁入对齐(单独 PR,涉及 spec-liveness-check.yml 的路径触发更新)。

OQ#9 — dispatcher vs rest-server 重叠审计(结论已记入 ADR)

判定:划清边界,不要合并。 二者在实际运行中按域瓜分 API 面而非互为冗余:标准启动下 REST 独占 data/meta/batch/导入导出/search/email/forms/sharing/reports/approvals/security,dispatcher 桥独占 mcp/ai/graphql/keys/automation/actions/storage/i18n/analytics/health/ready。真正双挂载的只有 discoverypackages 两处(注册序先到先得——正是 D11 要消除的味道);dispatcher 的 /data//meta//uidispatch() 分支在标准启动中并未挂载(仅当 HttpDispatcher 被树外适配器当 callable 直调时才活)。据此得出 D11 工作清单:①处理死的 callable 分支;②packages + discovery 各归一主;③按域抽取 handler;④环境解析统一到注入的 KernelResolver 缝。

变更内容

  • packages/qa/http-conformance/(新私有 QA 门:参照适配器 + 41 条一致性测试;不发布、无 changeset)
  • pnpm-workspace.yaml:新增 packages/qa/* glob
  • docs/adr/0076-objectql-core-tiering.md:OQ#9/OQ#10/OQ#11 标注 Resolved 并记录证据

验证

  • 一致性套件 41/41(含 CodeQL 修复后的原型污染回归测试);全 monorepo pnpm test 130/130 任务通过
  • changeset 守卫(no-major / fixed-group,69 个公开包)通过

🤖 Generated with Claude Code

https://claude.ai/code/session_01A1BtxNeUaGmvUYr8FwtUNu

…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
@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 2:40pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file tests tooling size/xl labels Jul 16, 2026
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/plugin-security, packages/qa, packages/services, @objectstack/spec.

104 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via packages/services, @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/services, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authorization.mdx (via @objectstack/plugin-security, packages/qa, @objectstack/spec)
  • content/docs/permissions/delegated-administration.mdx (via packages/qa)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-security, packages/services, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/services, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Comment thread packages/plugins/plugin-node-server/src/adapter.ts Fixed
claude added 2 commits July 16, 2026 08:32
…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
@os-zhuang os-zhuang changed the title ADR-0076 D11 前置验证:第二个 IHttpServer 适配器(裸 node:http)+ OQ#9/10 结论 (#2462) ADR-0076 D11 前置验证:HTTP 端口一致性门(packages/qa/http-conformance)+ OQ#9/10 结论 (#2462) Jul 16, 2026
… (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
claude added 3 commits July 16, 2026 13:14
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
@github-actions github-actions Bot added the ci/cd label Jul 16, 2026
claude added 2 commits July 16, 2026 13:50
…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
claude added 3 commits July 16, 2026 14:10
…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
@github-actions github-actions Bot removed the size/xl label Jul 16, 2026
@os-zhuang os-zhuang marked this pull request as ready for review July 16, 2026 14:57
@os-zhuang os-zhuang merged commit 1ab8752 into main Jul 16, 2026
17 of 18 checks passed
@os-zhuang os-zhuang deleted the claude/objectql-protocol-layering-s2sn67 branch July 16, 2026 14:58
@os-zhuang os-zhuang restored the claude/objectql-protocol-layering-s2sn67 branch July 16, 2026 15:06
os-zhuang pushed a commit that referenced this pull request Jul 16, 2026
os-zhuang pushed a commit that referenced this pull request Jul 16, 2026
…aned search-conformance files

- build-probes.test.ts publish suite: spy promoteDraftForPublish +
  runPublishSideEffects (the batch no longer calls publishMetaItem per
  item, ADR-0067 D2). objectql suite back to 904/904.
- The #3037 packages/dogfood -> packages/qa/dogfood restructure merged
  concurrently with #3065 and did not carry its three just-added files;
  they were orphaned at the old path outside every workspace (silently
  not running in CI). git mv them to packages/qa/dogfood/test — all 5
  dogfood suites green at the new home (21 tests).
os-zhuang added a commit that referenced this pull request Jul 16, 2026
* feat(transport): prove the IHttpServer port is Hono-free — second adapter 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

* fix(plugin-node-server): harden query/params against prototype pollution (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

* fix(plugin-node-server): eliminate the dynamic property-write sink CodeQL 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

* refactor(qa): reposition the port-conformance adapter as a private QA 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

* refactor(qa): migrate dogfood + downstream-contract into packages/qa/ (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

* chore: retrigger CI — Actions did not fire on dc6507c

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

* docs(changeset): fix dogfood path breadcrumb after packages/qa migration

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

* fix(ci): build the examples' dependency closure explicitly in the typecheck 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

* fix(ci): cap turbo test concurrency at the runner's core count (OOM mitigation)

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

* fix(qa): bump repo-relative path in the newly-merged declarative-mcp 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

* ci: TEMPORARY #3071 diagnostics — isolated verbose plugin-audit runs + 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

---------

Co-authored-by: Claude <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 16, 2026
…mit cannot half-land (ADR-0067 D2, #3066) (#3074)

* feat(metadata-protocol/objectql): turn-atomic package publish (ADR-0067 D2, #3066)

Phase 1: every draft promotion + the sys_metadata_commit record run inside
ONE engine.transaction() — a mid-batch failure rolls back everything
(publishedCount 0; causal item carries its real error, the rest report
batch_aborted). publishMetaItem is split into promoteDraftForPublish
(guards + promote, metadata-only) and runPublishSideEffects so the batch
can transact promotions while deferring side effects.

Phase 2 (post-commit): registry refresh, DDL, seed batch apply,
materializers, ADR-0094 projections, events — best-effort, surfaced via
materializeApplied.failures instead of faking an unpublish (metadata is
live; boot reconciliation heals side-effect drift).

objectql: engine.transaction() now JOINS an already-open ambient
transaction instead of opening a nested driver transaction — a nested
begin deadlocks single-connection pools (SQLite knex) and escapes the
outer rollback. Locked by two new engine-ambient-transaction tests.

BREAKING (behavioral): consumers relying on partial batch publishes now
get all-or-nothing. Engines without transaction() keep the previous
sequential behavior (same fallback stance as the repo's withTxn).

Tests: publish contract suite rewritten to the two-phase seams (+4 new
cases incl. rollback/commit tracking and side-effect-failure surfacing);
commit-history suite updated; 29 green across the three suites.

* fix(tests): migrate build-probes spy to the phase-1 seam; rescue orphaned search-conformance files

- build-probes.test.ts publish suite: spy promoteDraftForPublish +
  runPublishSideEffects (the batch no longer calls publishMetaItem per
  item, ADR-0067 D2). objectql suite back to 904/904.
- The #3037 packages/dogfood -> packages/qa/dogfood restructure merged
  concurrently with #3065 and did not carry its three just-added files;
  they were orphaned at the old path outside every workspace (silently
  not running in CI). git mv them to packages/qa/dogfood/test — all 5
  dogfood suites green at the new home (21 tests).

* docs(adr-0067): flip to Accepted — Decision-2 turn-atomicity lands with this PR (#3066)

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants