feat(core,cli): ship the DE parallel router fleet-wide — remove the canary gate

Deletes the `de-parallel-router` canary entry and the `isCanaryEnabled` guard
in render.ts together, leaving the producer's default-ON in place. Net effect
for users: the parallel drawElement router is on for everyone again.

## Why, and why not a ramp

Gating at 5% was itself the regression. Measured 2026-08-08, the day after
v0.7.101 shipped the canary: fleet router exposure fell from 3.13-4.25% of
non-CI renders to **0.13%**, roughly 25x, because out-of-cohort installs are
explicitly disarmed and #2840 deleted the everyone-armed trial in the same
change. 2,537 installs lost a feature they already had. Severity is speed
only, never output, and nothing is persisted to disk.

PR #2840's body claimed "the canary does not make exposure smaller; it makes
it chosen and revertible." That was true of the end state and false of the
first step. This lands the end state.

Entry and guard go together deliberately: at >=100 the evaluator
short-circuits ahead of the CI/seedless exclusions, so removing only the entry
would have flipped whatever still resolved false at deletion time, unstaged.

## Both stated blockers are void

- **≤4-CPU / Docker coverage gap.** Docker renders never use drawElement — 0
  of 4,281 across every CPU tier, software GL gates it out — and the router
  requires it. No percentage could ever expose Docker, so no ramp closes that
  gap. ≤4 CPUs yields ~42 drawElement candidates in three days.
- **PRINFRA-372.** Its signature has hits on 0.4.12, 0.4.37, 0.6.52, 0.6.93,
  0.6.109 and 0.6.110 — versions predating drawElement (v0.7.38) and therefore
  this router. It is real, still live on 0.7.101, and belongs to the
  screenshot/beginframe path. 11 reproduction runs across four configurations
  on the enriched profile (darwin/arm64 25.5.0) came back clean.

## Safety unchanged

The per-install circuit breaker and the per-render self-verify are untouched;
`HF_DE_PARALLEL_ROUTER=false` remains the user-facing kill switch. Post-canary
data at 14 days: >8 CPUs 3.02% revert (177/5,857), 5-8 CPUs 2.40% (6/250) —
consistent with the 2.75-3.16% baseline.

Revert path is now a code revert rather than a registry edit. That is the
trade this shape accepts in exchange for one release instead of two.

## Corrects two claims that shipped wrong

`~17x jump in exposure onto <=4 CPUs / Docker` overstated the reach, and
`~11% of installs already route` was an OUTCOME (the share clearing
eligibility and the old 25-render cap), not an exposure setting — read as a
rollout knob it inverts the arithmetic, which is how gating at 5% came to cut
exposure rather than ramp it. Both are recorded in render.ts so they are not
reintroduced.

## Tests

Removed the core wiring assertion and the two CLI canary-gating tests, which
pinned a gate that no longer exists. Added the inverse guarantee in its place:
an ordinary install must come out of the breaker with the var UNSET so the
producer default applies — writing "false" there is precisely what disarmed
the fleet at 5%.

core 1701 passing, cli 2491 passing, studio canary 29 passing. The 2 failures
in play.test.ts reproduce on clean origin/main and are unrelated (#3114 area).
oxlint and oxfmt clean.

Note: telemetry for this rollout stops with the entry — `$feature/canary-de-parallel-router`
and `canary_reason_de_parallel_router` are emitted from the registry, so the
`Ramp —` tiles and the exposure-floor alert on PostHog dashboard 1918875 go
blank once this ships. Watch drawElement engagement on 1807532 instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-08-08 14:10:25 -07:00
co-authored by Claude Fable 5
parent b1f7d8881b
commit 19defeabfe
5 changed files with 31 additions and 107 deletions
+5 -26
View File
@@ -1,6 +1,4 @@
import { describe, expect, it } from "vitest";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { canaryBucket, evaluateCanary, parseCanaryOverride, type CanaryInput } from "./canary.js";
import { CANARIES, canaryEnvVar, findCanary, overdueCanaries } from "./canaryRegistry.js";
import {
@@ -293,29 +291,10 @@ describe("registry", () => {
}
});
// The registry is data, so a ramp is a one-line edit with no code review
// surface. This canary's own description says "ramp only alongside the
// per-install circuit breaker" — without an assertion, bumping it to 5
// before that wiring lands would go green.
// The registry is data, so a ramp is a one-line edit with no code review
// surface. The previous version enforced "ramp only alongside the circuit
// breaker" by pinning the percentage to 0 — which blocks the ramp forever
// and never checks the wiring it names.
//
// Assert the wiring instead: a non-zero percentage is allowed only while
// the CLI render path really gates on this canary AND still consults the
// per-install breaker. Ramping without the gate would enrol everybody at
// once, which is the whole thing the ramp exists to prevent.
it("only ramps de-parallel-router while the CLI render path gates on it", () => {
const pct = findCanary("de-parallel-router")?.percentage ?? 0;
if (pct === 0) return;
const renderSrc = readFileSync(
join(import.meta.dirname, "..", "..", "cli", "src", "commands", "render.ts"),
"utf8",
);
expect(renderSrc).toContain('isCanaryEnabled("de-parallel-router")');
expect(renderSrc).toContain("deParallelRouterTrialFired");
});
// The de-parallel-router wiring assertion that lived here was removed with
// the canary itself (registry entry + render.ts guard, same commit). The
// per-install circuit breaker it referenced is unchanged and is covered by
// the CLI's own render tests.
it("has in-range percentages and a parseable sunset date", () => {
for (const c of CANARIES) {
@@ -329,7 +308,7 @@ describe("registry", () => {
it("derives the override env var from the name", () => {
expect(canaryEnvVar("de-parallel-router")).toBe("HF_CANARY_DE_PARALLEL_ROUTER");
expect(findCanary("de-parallel-router")?.name).toBe("de-parallel-router");
expect(findCanary("calibration-10")?.name).toBe("calibration-10");
expect(findCanary("nope")).toBeUndefined();
});