Skip to content

feat(showcase): live provider:'mcp' declarative connector demo + CI-pinned dogfood proof (#3056)#3062

Merged
os-zhuang merged 6 commits into
mainfrom
claude/adr-0097-default-preset
Jul 16, 2026
Merged

feat(showcase): live provider:'mcp' declarative connector demo + CI-pinned dogfood proof (#3056)#3062
os-zhuang merged 6 commits into
mainfrom
claude/adr-0097-default-preset

Conversation

@os-zhuang

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

Copy link
Copy Markdown
Contributor

实现 #3056showcase 演示部分:落地 ADR-0097 最初设想的 provider: 'mcp' 验收演示(#3017 延后项),并用 dogfood 测试把它钉进 CI。前置安全闸 #3055(默认拒绝声明式 stdio)已随 #3059 合入,本 PR 是其第一个 dogfood 用户。

范围说明:#3056 的另一半——create-objectstack 模板默认内置三个通用执行器——首版曾包含在本 PR,但 scaffold-e2e 作业从 npm registry 安装脚手架应用,而 ConnectorOpenApiPlugin#3055declarativeStdio 只存在于未发布的 15.1.0(排队于 Changesets release PR)。模板不能引用未发布 API(真实 npm create objectstack 用户会同样炸),故该部分已从本 PR 移除,待 15.1.0 发布后作为小跟进落地(届时模板现有 ^15.0.0 pin 自然解析到 15.1.0)。#3056 保持打开跟踪。

变更

showcase:live provider: 'mcp' 演示(CI 确定性)

  • scripts/mcp-fixture.mjs —— 仓内极小 stdio MCP 服务器,一个确定性工具 echo_upper。选 stdio fixture 而非 http 自连:spawn 发生在 materialization 时刻,无网络、无端口、无启动时序耦合,Dogfood 门不会时序抖动。
  • DevToolsMcpConnector(provider: 'mcp',transport node ./scripts/mcp-fixture.mjs)+ ShowcaseMcpConnectorEchoFlow(connector_action → echo_upper,输出变量携带 structuredContent)。
  • objectstack.config.ts 接线 new ConnectorMcpPlugin({ declarativeStdio: ['node'] }) —— dogfood feat(connector-mcp): policy-gate declarative stdio transports — default-deny + host allowlist (ADR-0097 security follow-up) #3055 的 opt-in,注释如实说明粗粒度信任边界;coverage 注记同步(三个通用执行器的声明式实例现已全部演示)。

dogfood:把演示钉进 CI

showcase-declarative-mcp.dogfood.test.ts 启动真实 showcase(chdir 到应用根,与 os dev 的运行方式一致;vitest 每文件独立进程,chdir 隔离),经 extraPlugins 注入三个执行器(bootStack 不装配 stack 的 plugins:),断言:

  1. GET /automation/connectors 列出 showcase_mcp_tools:origin: 'declarative'state: 'ready'、含 echo_upper(即 fixture 成功 spawn + tools/list 映射);rest/openapi 姊妹实例同样 ready;catalog descriptor 不在注册表;
  2. 触发 flow → run 成功且输出含 OBJECTSTACK(fixture 的 tools/call 结果完成全链路往返)。

文档

content/docs/automation/flows.mdx 节点表后新增一段:connector_action 的连接器从哪来、三个通用执行器与声明式 provider 条目的关系(showcase 已全部接线)、stdio opt-in 的安全语义。

验证

  • dogfood 新证明 2/2 ✓;turbo test(dogfood + showcase + create-objectstack)63 任务全绿 ✓
  • showcase validate(23 flows / 8 plugins)+ typecheck + 55 测试 ✓;eslint ✓;lockfile 已更新(showcase/dogfood 新依赖)

Refs #3056(showcase 演示部分;模板预设部分待 15.1.0 发布)、#3055 / #3059#3017 / #3049、ADR-0097 §6。

🤖 Generated with Claude Code

https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs

claude added 5 commits July 16, 2026 11:31
…e upstream (#3017)

ADR-0097 made every declarative-connector materialization failure fatal at
boot — right for configuration faults, wrong for operational ones: a
provider: 'mcp' instance must contact its MCP server (tools/list) to
materialize, so a transient network blip aborted the whole app boot.

- spec: ConnectorUpstreamUnavailableError (code CONNECTOR_UPSTREAM_UNAVAILABLE,
  structural guard isConnectorUpstreamUnavailable) lets a provider factory mark
  a failure as 'upstream temporarily unreachable — degrade and retry' instead
  of fatal. New integration/connector-provider-errors.ts; api-surface +3.
- service-automation: the reconcile degrades such instances in BOTH modes.
  With no live connector under the name it registers an action-less husk —
  state: 'degraded' + degradedReason on the GET /connectors descriptor,
  status: 'error' on the def — so the instance stays visible instead of
  silently missing; connector_action dispatch fails with the reason and a
  'retries automatically' pointer. On a changed-config re-materialization the
  old connector keeps serving. Degraded instances retry on an exponential
  backoff (5s doubling to 5min, reset by config edits) and on every
  metadata:reloaded reconcile; recovery swaps the husk atomically. Reconcile
  runs (boot / reload / retry timer) are serialized; destroy() cancels the
  retry loop.
- connector-mcp: connect / tools/list failures are classified unavailable;
  transport-shape validation stays a plain (fatal) throw.

Configuration faults (unknown provider, invalid providerConfig, unresolvable
credentialRef, name conflicts) keep the ADR-0097 fail-loud contract, verified
by the existing tests. ADR-0097 gains an 'Upstream availability' section; the
deferred live-mcp showcase demo and the openapi remote-URL classification are
recorded as scope boundaries.

Tests: 10 new reconcile cases (degrade visibility, pointed dispatch error,
fake-timer recovery, exponential backoff, reload retry, removal while
degraded, changed-config keeps old serving, revert cancels retry, shutdown
cancels retry, plain-throw still fatal); 3 new mcp-provider classification
cases; 3 new spec error-contract cases.

Refs #3017 (mechanism; showcase demo deferred — see ADR scope boundaries)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs
…lt-deny + host allowlist (#3055)

A declarative provider: 'mcp' entry with a stdio transport spawns a local
child process from METADATA — which a runtime Studio publish can introduce
(the reload reconcile materializes new instances; soft mode skips failures,
not successes). Anyone who can publish metadata could otherwise execute
arbitrary commands on the server. Declarative stdio is now denied by default
and opt-in per host:

  new ConnectorMcpPlugin({ declarativeStdio: ['my-mcp-server'] })  // allowlist
  new ConnectorMcpPlugin({ declarativeStdio: true })               // full trust

- createMcpProviderFactory gains a declarativeStdio policy (undefined/false =
  deny, string[] = strict-equality command allowlist, true = allow any);
  ConnectorMcpPlugin plumbs it through. New export McpDeclarativeStdioPolicy.
- A violation is a CONFIGURATION fault: plain throw with an actionable opt-in
  message (fatal at boot, skipped+logged on reload) — never classified
  CONNECTOR_UPSTREAM_UNAVAILABLE, so a security rejection cannot be retried
  into existence (#3049 seam).
- http transports are unaffected (same trust class as the http node), and so
  are hand-wired connectors (plugin instance options / createMcpConnector) —
  their command lives in host code, a different trust anchor than metadata.
- ADR-0097 gains a 'Declarative stdio policy' section (cross-ref ADR-0024 §4,
  honest about the allowlist being a coarse boundary); this gate is the
  precondition for shipping connector-mcp in default presets (#3056).

Tests: default-deny (plain, non-retryable, rejected before any connection
attempt), allowlist hit/miss, true passthrough, http unaffected, plugin
option plumb-through, hand-wired stdio path explicitly un-gated (e2e).

Refs #3055. Stacked on #3049 (claude/adr-0097-mcp-nonfatal-boot).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs
#3049's squash (4f8c2d1) is content-identical to this branch's base commit,
so this merge only rebases the PR surface — the three-dot diff vs main now
shows the #3055 gate alone.

# Conflicts:
#	docs/adr/0097-declarative-connector-instances.md
#	packages/connectors/connector-mcp/src/mcp-provider.test.ts
#	packages/connectors/connector-mcp/src/mcp-provider.ts
…ve provider:'mcp' showcase demo (#3056)

Closes the last authoring gap in ADR-0097's 'expressible AND executable as
pure metadata' promise, and lands the provider:'mcp' acceptance demo the ADR
originally envisioned (deferred at #3017).

create-objectstack (blank template):
- plugins: gains new ConnectorRestPlugin() / ConnectorOpenApiPlugin() /
  ConnectorMcpPlugin() (zero-arg = provider factory only), so a scaffolded
  app materializes declarative provider-bound connectors with no
  plugin-wiring step. README documents the default providers, credentialRef
  rule, and the #3055 declarativeStdio opt-in. Deps added at ^15.0.0.

examples/app-showcase (live mcp demo):
- scripts/mcp-fixture.mjs — tiny in-repo stdio MCP server (one deterministic
  echo_upper tool): no network, no ports, no boot-ordering coupling, so the
  demo is CI-deterministic.
- DevToolsMcpConnector (provider: 'mcp', stdio transport 'node
  ./scripts/mcp-fixture.mjs') + ShowcaseMcpConnectorEchoFlow dispatching
  echo_upper end-to-end; coverage notes updated.
- objectstack.config.ts wires new ConnectorMcpPlugin({ declarativeStdio:
  ['node'] }) — dogfooding the #3055 default-deny opt-in, with the
  coarse-boundary caveat spelled out.

dogfood:
- showcase-declarative-mcp.dogfood.test.ts boots the REAL showcase (chdir to
  the app root, exactly how os dev runs), injects the three executors, and
  pins: GET /connectors lists showcase_mcp_tools origin=declarative
  state=ready with echo_upper (rest + openapi siblings ready too; catalog
  descriptor absent), and the flow trigger round-trips OBJECTSTACK from the
  fixture's tools/call into the run output.

docs: flows.mdx explains where connector_action connectors come from, the
default preset, and the stdio opt-in.

Verified: dogfood proof 2/2; turbo test dogfood+showcase+create-objectstack
63 tasks green; showcase validate (23 flows / 8 plugins) + typecheck clean;
eslint clean; lockfile updated for the new deps.

Refs #3056 (template + showcase + demo + docs; issue also tracks nothing
further after this — see closing comment)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs
@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:37pm

Request Review

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

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/dogfood.

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

  • content/docs/permissions/authorization.mdx (via packages/dogfood)
  • content/docs/permissions/delegated-administration.mdx (via packages/dogfood)

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.

…he 15.1.0 publish

The scaffold-e2e job installs the generated app from the npm REGISTRY, and
ConnectorOpenApiPlugin (and the #3055 declarativeStdio option) only exist in
the unpublished 15.1.0 (queued in the Changesets release PR). A template must
not reference unpublished APIs — the same failure would hit real
'npm create objectstack' users. Reverted the template files + changeset;
once 15.1.0 publishes, the template's ^15.0.0 pins resolve to it and the
preset piece lands as a small follow-up. flows.mdx reworded to describe the
mechanism without the scaffold claim.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pbmw3pMqNJfPbkvwh9Fkjs
@os-zhuang os-zhuang changed the title feat: default preset ships the three generic connector executors + live provider:'mcp' showcase demo (#3056) feat(showcase): live provider:'mcp' declarative connector demo + CI-pinned dogfood proof (#3056) Jul 16, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review July 16, 2026 14:09
@os-zhuang
os-zhuang merged commit f8663b8 into main Jul 16, 2026
17 of 18 checks passed
@os-zhuang
os-zhuang deleted the claude/adr-0097-default-preset branch July 16, 2026 14:09
os-zhuang pushed a commit that referenced this pull request Jul 16, 2026
…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
os-zhuang added a commit that referenced this pull request Jul 16, 2026
…结论 (#2462) (#3037)

* 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

---------

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants