Skip to content

ci(node): add paired SDK performance benchmarks - #5453

Open
dustinbyrne wants to merge 2 commits into
mainfrom
feat/node-performance-benchmarks
Open

dustinbyrne wants to merge 2 commits into
mainfrom
feat/node-performance-benchmarks

Conversation

@dustinbyrne

Copy link
Copy Markdown
Contributor

Problem

SDK changes need reproducible PR-local evidence for flag evaluation time, allocation churn, and memory amplification, rather than relying on anecdotes or retained heap alone.

Changes

  • Add 17 deterministic public-entry workloads covering individual/all flags, scaling, overlapping evaluation, definition refreshes, and capture/drain.
  • Run isolated, alternating base/head timing, V8 allocation-sampling, and memory passes with correctness checks and explicit failure/unsupported statuses.
  • Add a read-only PR workflow that builds the merge base and exact head, uploads paired JSON, and links artifacts from the job summary. Performance measurements are informational.
  • Document measurement boundaries and limitations. No SDK runtime behavior or release changes.

Shared report rendering and commenting will integrate in a stacked follow-up.

Validation

  • 12 benchmark controls passed, including public-entry CPU/allocation regression controls, collected-allocation coverage, payload validation, build identity, and worker failures.
  • 282 existing feature-flag tests passed.
  • Complete local same-commit comparison: 17 workloads, six paired repetitions, 372 successful workers, 394.56 seconds (Node 24.13.0, macOS ARM64; excludes install/build).
  • Scoped lint/format, Actionlint, and diff checks passed. Linux CI calibration remains to be established.

Release info

No version bump or changeset: benchmark/CI tooling only.

Agent context

Autonomy: Human-driven (agent-assisted).
Implemented using Pi, with a fresh read-only reviewer and local measurement controls. Separate passes keep profiler overhead out of timing; sampled allocation bytes and observed/lifetime RSS retain explicit scope and quality.

@dustinbyrne
dustinbyrne requested a review from a team as a code owner October 27, 2026 21:39
@dustinbyrne dustinbyrne self-assigned this Oct 27, 2026

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not approved yet — waiting on the conditions below.

Re-add the stamphog label to request another review once you have addressed this.

stamphog declined to auto-review this pull request because three gates failed. The deny-list gate matched infra_cicd, since the PR adds .github/workflows/node-benchmarks.yml. The size gate found 815 substantive lines against an 800-line ceiling, and the tier gate classified the change as T2-never (two areas, CI). These are policy refusals and say nothing about the quality of the work.

Please ask a human reviewer to look at it. Splitting the workflow file from the benchmark code under packages/node/benchmarks/ would bring each part under the size ceiling, but the workflow change would still need human review.

Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✗ matches: infra_cicd
size ✗ too large for auto-review (815L substantive in global — ceiling is 800L; 815L, 7F total, 1171L/9F incl. docs/generated/snapshots)
tier ✗ classified as T2-never: T2-never (1171L, 9F, two-areas, ci)
stamphog 2.6.1 .stamphog/policy.yml @ unknown · reviewed head f726795

@github-actions

Copy link
Copy Markdown
Contributor
⚠️ `posthog-node` is modified but this PR has no changeset

This is informational — the PR is not blocked. Click the triangle above to collapse, or push a fix and this comment will auto-delete.

Modified in this PR but no changeset added:

  • posthog-node

If this change should ship, run pnpm changeset and select a bump level.
If it isn't user-facing (refactor with no behavior change, internal tooling, generated files), no action needed.

@stamphog stamphog Bot removed the stamphog label Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📝 No Changeset Found

This PR doesn't include a changeset. A changeset is required to release a new version.

How to add a changeset

Run this command and follow the prompts:

pnpm changeset

Remember: Never use major version bumps for posthog-js as it's autoloaded by clients.

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed f726795: 1 Must fix, 1 Should fix.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

@@ -0,0 +1,256 @@
import assert from 'node:assert/strict'
import { test } from 'node:test'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 · Exclude the Node benchmark tests from Vitest discovery

Running test:unit or test:edge-compat now discovers this file through Vitest's default glob, since the shared config does not exclude benchmarks/**. Its node:test registrations create no Vitest tests, so the existing suites fail with No test suite found. Exclude the benchmark directory from the shared Vitest configuration.

await save()
}
}
if (records.base.status !== 'ok' || records.head.status !== 'ok') break

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Bound repeated worker timeouts within the CI job budget

When full-size single-flag workloads hang on one revision, main breaks only the repetition loop and continues through every workload. Nine cases with two passes each consume 36 minutes in worker timeouts, exceeding the workflow's 30-minute limit and preventing diagnostic artifact upload. Stop after repeated timeouts or enforce a suite deadline that reserves upload time.

@github-actions

Copy link
Copy Markdown
Contributor

Coherence

0 spec problems · 0 failing chokepoints · 2 spec gaps · 0 guard failures

44 components, 7 bullets (5 invariants, 2 requirements), 0 problems

Chokepoints: none declared.

Spec gaps: 2 entrances with outside or unknown trust and no traced control, and 10 more held by the adoption baseline

  • packages/web/Web.spec.md entrance public api (trust host-app): packages/web
  • packages/webpack-plugin/Webpack-plugin.spec.md entrance webpack plugin (trust build): packages/webpack-plugin

Close one with guard: <chokepoint>, an invariant that names it on its entrances: line, or control: none — <reason>; scaffold control proposes it.

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Node SDK compliance v2

Commit: 94a1999
Workflow run and artifacts

Capture v0 — acceptance

✅ 28 passed / ❌ 3 non-passing / ⚠️ 853 not selected

Drill-down: run artifacts → node-v2-v0 → acceptance/report.json.diagnostics.json (match case_id below).

❌ server_snapshot_payload_false — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_zero — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_null — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:

Harness exit: 1; report validation exit: 1.

Capture v1 — acceptance

✅ 28 passed / ❌ 3 non-passing / ⚠️ 853 not selected

Drill-down: run artifacts → node-v2-v1 → acceptance/report.json.diagnostics.json (match case_id below).

❌ server_snapshot_payload_false — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_zero — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:
❌ server_snapshot_payload_null — failed_assertion

Expected native data result

Code: snapshot_result

Failed step: acceptance/public/evaluate-flags.feature:868

the public snapshot outcomes should have these semantics:

Harness exit: 1; report validation exit: 1.

Capture v0 — migration

✅ 55 passed / ❌ 1 non-passing / ⚠️ 101 not selected

Drill-down: run artifacts → node-v2-v0 → reports/report.json.diagnostics.json (match case_id below).

❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

Capture v1 — migration

✅ 120 passed / ❌ 1 non-passing / ⚠️ 36 not selected

Drill-down: run artifacts → node-v2-v1 → reports/report.json.diagnostics.json (match case_id below).

❌ migration/yaml-parity-v1/remote-flags-v1.feature::Omitted GeoIP settings default to enabled in flag requests — failed_assertion

Flags field differs

Code: flag_request_field

Failed step: migration/yaml-parity-v1/remote-flags-v1.feature:134

the first flags request field "geoip_disable" should equal JSON false

Operation: /flags/

Field: geoip_disable

Expected:

false

Actual value:

true

Harness exit: 1; report validation exit: 1.

@marandaneto marandaneto left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good; no qualifying findings. Verdict: correct.

This branch has not been deployed

No deployments
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.

2 participants