Files
WRNexusJS/docs/superpowers/specs/2026-08-19-legacy-and-config-cleanup-design.md
T
ClintchizandClaude Opus 5 68cc75d0b0 docs: fold the auth deprecations into the cleanup spec as a firm scope
They are our own superseded options, not a stale dependency. The recommended
form is already what the showcase example uses; the blast radius is three
test files inside packages/auth, and the rpId/origin options are already
ignored at runtime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 22:55:50 +05:30

12 KiB
Raw Blame History

Legacy, deprecated, and unused-config cleanup — Design

Date: 2026-08-19 Status: Approved for implementation Scope: Remove the compatibility-flag surface, the "legacy" function runtime, dead migrations, and deprecated APIs — before the framework's first public release.

Goal

WRNexus carries compatibility machinery for a public it does not yet have. Every branch of it is either switched off in the only apps that exist, or wired to nothing at all. Removing it now costs almost nothing; removing it after release costs a major version and other people's time.

Why this is safe now

Two pieces of evidence, both verified rather than assumed:

The only consumers already run without it, which matters for the config files themselves even though the keys are inert. D:\Company\wrnexus\apps\admin and D:\Company\wrnexus\apps\web — both test projects, neither deployed — set every compatibility flag to false and legacyDefaultRuntime: "current". They are already on the modern path; removing the flags means deleting the lines that say "off".

None of the seven keys change any behaviour. Verified by tracing every reference, not by reading the types. legacyEmit, legacyEventProps, legacyComponentDiscovery, stringLayouts, and legacyDefaultRuntime appear in exactly three places each: the type declaration in config.ts, the scaffolder in create.ts, and the insertion in update.ts. No compiler, codegen, or runtime code reads any of them. They are written into every generated config and then ignored.

The remaining two are the same story with more machinery. resolveCompatibility (packages/styles/src/compatibility.ts) produces a report — an effective date, a behaviour number, and advisory strings. Tracing every consumer: the wrnexus compatibility command prints it, and config.ts raises one validation error when the configured date is newer than the CLI supports. No compiler branch and no runtime behaviour reads effectiveDate or effectiveBehaviour. The mechanism is scaffolding that was never connected.

Non-goals

  • The legacy api block forms. Bare-body blocks using with ($data), and api entries inside ssr {} / client {}, are replaced rather than deleted — that is the next spec's job. Removing them here would leave a gap with no working mechanism.
  • Adding any configuration key. This spec only removes them.
  • Changing any behaviour that is currently switched on.

What gets removed

Item Where Why it goes
compatibility: { legacyEmit, legacyEventProps, legacyComponentDiscovery, stringLayouts } packages/styles/src/config.ts (CompatibilityConfig) Never read by any code
functions: { legacyDefaultRuntime } packages/styles/src/config.ts (FunctionsConfig) Never read by any code
compatibilityDate packages/styles/src/compatibility.ts (CompatibilityPolicy) Gates nothing
frameworkBehaviour same Gates nothing
resolveCompatibility, CompatibilityReport, isCompatibilityDate, CURRENT_COMPATIBILITY_DATE, CURRENT_FRAMEWORK_BEHAVIOUR packages/styles/src/compatibility.ts Whole module serves only the two dead keys
wrnexus compatibility <check|explain|upgrade> packages/cli/src/compatibility-command.ts, dispatch at packages/cli/src/index.ts:295, help text at :75 Reports on removed keys
"legacy" variant of FunctionRuntime packages/syntax/src/v060.ts, branches in packages/compiler/src/client-codegen.ts and server-codegen.ts An unmarked function becomes shared (see below)
Migrations below 0.8.0 packages/cli/src/update.ts 111 migrations reach back to 0.2.8; no project exists below 0.8.x
Deprecated re-export shims packages/compiler/src/{parser,tokenizer,types}.ts Two lines each, re-exporting @wrnexus/syntax
Deprecated @wrnexus/auth options engine.ts (4 sites), http/index.ts (2), plugin.ts (2), types.ts (1) See "Deprecated auth options"

The "legacy" function runtime

FunctionRuntime is "legacy" | "client" | "server" | "shared". "legacy" is what an unmarked function foo() gets, and legacyDefaultRuntime decides how it behaves. Both codegens then test membership: ["legacy", "client", "shared"] for the browser and ["legacy", "server", "shared"] for the server — which is to say an unmarked function is currently emitted into both bundles, exactly like shared.

legacyDefaultRuntime looks like it should modulate this, but it is never read (above), so the mapping is unconditional: unmarked is always "legacy", and "legacy" is always emitted to both bundles.

So the removal is mechanical: delete the "legacy" variant, and parse an unmarked function as "shared". The emitted output for every existing unmarked function is unchanged, in every configuration. FunctionRuntime becomes "client" | "server" | "shared", and the membership tests lose one element each.

This is the one item where behaviour could drift if done carelessly, so its test is explicit: an unmarked function must still appear in both the browser and server modules.

Deprecated re-export shims

packages/compiler/src/parser.ts, tokenizer.ts, and types.ts are two-line files re-exporting @wrnexus/syntax. They are marked deprecated, but codegen.ts and native-codegen.ts still import from them, so deleting the files is not enough — those imports must be repointed at @wrnexus/syntax first. Removing the files without that step breaks the build.

Deprecated auth options

@wrnexus/auth carries nine @deprecated markers. These are our own superseded options, not an out-of-date dependency — there is no newer version to move to, only newer options we already added. Removing them means deleting the old aliases and moving the few call sites that still use them.

Group Where Replacement Still used?
onSignedIn / onSignedOut on HTTP route options and plugin options http/index.ts, plugin.ts the same names on createAuthEngine({ … }) only packages/auth/test/http.test.ts and plugin.test.ts
onSuccessfullSignUp (misspelled alias) types.ts onSuccessfulSignUp nowhere — zero references
rpId / origin on passkey verification engine.ts (4 sites) values bound to the issued challenge packages/auth/test/engine.test.ts

Two things this table settles:

  • The recommended form is already in use. examples/auth-showcase/app/lib/auth.ts passes onSignedIn / onSignedOut to createAuthEngine, which is the current API. The deprecated members are the same names on different option objects, so the example needs no change.
  • Neither test app uses any of them. Nothing in D:\Company\wrnexuspps references these options.

So the blast radius is three test files inside packages/auth, which are exercising the deprecated paths and are updated or removed alongside them. The rpId / origin options are already ignored at runtime — verification uses the values bound to the issued challenge — so removing them changes no behaviour, only the shape of the call.

Migration

examples/basic-app and both test apps need one pass each:

  1. Delete compatibility, functions, compatibilityDate, and frameworkBehaviour from wrnexus.config.ts — seven lines per app.
  2. packages/cli/src/create.ts stops scaffolding those keys, so new apps get a shorter config.

No .wrn source changes. Nothing in this spec alters page syntax.

The removed 0.2.x0.7.x migrations mean a project below 0.8.0 can no longer be upgraded by wrnexus update. No such project exists, and rescuing one would be a manual job either way.

Testing

  • The "legacy" runtime removal is behaviour-preserving: an unmarked function still appears in both the browser and server modules. This is the assertion most worth writing, because it is the only removal that could silently change output.
  • Config rejects the removed keys rather than ignoring them, so a stale config fails loudly with a message naming the key. A silently-ignored key would leave someone believing a flag still applies.
  • create.ts scaffolds a config without them, asserted against the generated file.
  • wrnexus update still runs with the pre-0.8.0 migrations gone, and reports correctly for an app already at the current version.
  • examples/basic-app builds and its suite passes after its config is trimmed — the end-to-end guard that nothing depended on the removed surface.
  • The full gate (bun run check:production) passes, including the editor bundles, which embed the compiler and must be rebuilt after FunctionRuntime changes.

What we give up

Deleting compatibilityDate and frameworkBehaviour removes the standard escape hatch for changing a default after going public — the mechanism that lets an existing app keep old behaviour by pinning a date. Today it is wired to nothing, so it protects nobody, and an unused mechanism rots rather than matures. If a gate is needed later it can be reintroduced deliberately, against a real behaviour change, instead of being carried empty. This is a considered trade rather than a free deletion.