Strata architecture and SDDMenu
On this page

Analog integration baseline

Generated by pnpm test:analog at 2026-10-28T16:56:05.925Z. This report is regenerated on every run; it reflects the most recent execution against baseline 02b06a17dbd5e9221bf02367beadabfbf84e54ee.

Scope. One question: how does the current @strata-sc/core / @strata-sc/h3 fit inside a real Angular + Analog application (apps/analog-fixture), built and run with the stock Analog pipeline? No Strata Vite plugin and no decorator transform. @strata-sc/core decorators are used in src/server/**, and @strata-sc/analog registers a controller on the Nitro router through Nitro's public plugin API. It makes no claim beyond the single tuple below and the two modes exercised (dev server, production server).

Result of this run: every recorded expectation held.

Exact dependency tuple

Node v22.23.1, pnpm 10.30.1. The fixture's manifests follow the official create-analog@2.7.2 template-latest. "Resolved" is read from the installed packages on disk (symlinks followed), not from package.json.

PackageDeclaredResolvedNote
@angular/core^22.2.322.2.3Angular runtime
@angular/compiler-cli^22.2.322.2.3Angular compiler (ngtsc)
@angular/build^22.0.022.1.8Angular build tooling used by the Analog plugin
@analogjs/platform^2.7.22.7.2Analog (Vite platform plugin)
@analogjs/vite-plugin-angular^2.7.22.7.2Analog's Angular compiler integration
@analogjs/router^2.8.12.8.1Analog file router
vite^8.0.08.3.0Fixture-local Vite
typescript~6.0.06.0.3TypeScript
tslib^2.3.02.8.1TypeScript helper library
@analogjs/vite-plugin-nitro(transitive)2.7.2Analog's Nitro integration
nitropack(transitive)2.13.4Nitro 2 — the HTTP runtime
vite(transitive)8.1.5Vite bundled by @angular/build
@strata-sc/coreworkspace:*0.2.2workspace link
h3^1.15.111.15.11H3 used by nitropack (Nitro 2)
h3^2.0.1-rc.12.0.1-rc.32H3 used by @strata-sc/h3

Lockfile (pnpm-lock.yaml, packages: section) — every version present in the whole workspace graph:

PackageVersions in lockfile
@analogjs/platform2.7.2
@angular/build22.1.8
@angular/core22.2.3
h31.15.11, 2.0.1-rc.32
nitronone
nitropack2.13.4
rolldown1.1.5, 1.2.0, 1.2.8
typescript6.0.3
vite8.1.5, 8.3.0

Runtime graph: which H3?

h3 as resolved from each consumer, and the top-level APIs that copy actually exports (loaded from disk, not inferred):

Resolved fromh3createAppcreateRoutercreateEventH3 class
nitropack1.15.11yesyesyesno
@analogjs/vite-plugin-nitro1.15.11yesyesyesno
@strata-sc/h32.0.1-rc.32yesyesnoyes
  • Resolved Nitro: 2.13.4 (nitropack, preset node-server), recorded by the built server in dist/analog/nitro.json. Production start command: node dist/analog/server/index.mjs.
  • The built production server does not load an installed h3: Nitro inlines it into dist/analog/server/chunks/nitro/nitro.mjs, which defines createApp: yes, createRouter: yes and an H3 v2 H3 class: no.
  • Analog/Nitro run H3 v1; @strata-sc/h3 targets H3 v2. They are different majors with different APIs (createApp/createRouter vs the H3 class).

Angular/Analog compilation and standard decorators

The same consumer-authored @Controller() / @Get() (standard TC39 decorators from @strata-sc/core) was observed in the two places Analog compiles TypeScript. Classes: A works, B compile-time failure, C build succeeds but runtime fails, D other.

ArmPipelineModeExpectedObservedEvidence
S-devStrata controller via @strata-sc/analog (nitroApp.router)dev serverAA200 [{"id":"1","name":"Ada"}]
S-prodStrata controller via @strata-sc/analog (nitroApp.router)production serverAA200 [{"id":"1","name":"Ada"}]
N-devNitro server route (src/server/**)dev serverAA200 {"source":"strata-core","definition":{"path":"/hello","routes":[{"method":"GET","path":"/","handler":"hello"}]},"invoked":{"message":"Hello from Strata","marker":"STRATA_ANALOG_SERVER_ONLY_MARKER"}}
N-prodNitro server route (src/server/**)production serverAA200 {"source":"strata-core","definition":{"path":"/hello","routes":[{"method":"GET","path":"/","handler":"hello"}]},"invoked":{"message":"Hello from Strata","marker":"STRATA_ANALOG_SERVER_ONLY_MARKER"}}
G1Angular-compiled graph (page → controller)production build, stock tsconfigBBRolldownError: <repo>/apps/analog-fixture/src/probes/angular-graph/probe.controller.ts:7:1: Unable to resolve signature of class decorator when called as an expression. / The runtime will invoke the decorator with 1 arguments, but the decorator expects 2. / <repo>/apps/analog-fixture/src/probes/angular-graph/probe.controller.ts:9:4: Unable to resolve signature of method decorator when called as an expression.
G2-buildAngular-compiled graph (page → controller)production build, experimentalDecorators: falseAAbuild succeeded
G2-prodAngular-compiled graph (page → controller)production server (SSR of the probe page)CCHTTP 200; page did not render the expected definition; server log: ERROR Error [ERR_MODULE_NOT_FOUND]: Cannot find module '<repo>/apps/analog-fixture/dist/analog/server/node_modules/tslib/modules/index.js' imported from /Volumes/WorkStation/projects/Strata/apps/analog-fixture/dist/analog/server/chunks/_/decorator-probe.page-LA4lckFK.mjs; tslib files traced into dist/analog/server/node_modules: package.json, tslib.es6.mjs
G2-devAngular-compiled graph (page → controller)dev server (SSR of the probe page)AAHTTP 200; page rendered the expected definition
  • Nitro server routes (src/server/**, native Analog API routes) are bundled by Nitro's own Rollup + esbuild pipeline, not by the Angular compiler. esbuild lowers standard decorators on its own; getControllerDefinition() returns the right metadata in dev and production.
  • The Angular-compiled graph (pages, components, anything a page imports) uses the stock Analog template's experimentalDecorators: true: the Angular compiler type-checks the consumer's decorators as legacy decorators and fails the build (class B). With experimentalDecorators: false the decorators are lowered and the metadata is correct in the dev server, but the production server's SSR of that page fails (class C).
  • Nothing here modified Strata or added a transform. The baseline build uses the stock vite.config.ts; the G arms use vite.probe.config.ts, which differs only by also building the probe page and by selecting which tsconfig Analog's Angular plugin reads.

Production build

pnpm --filter @strata-fixtures/analog run build (vite build) exit status: 0.

ArtifactPresentRole
dist/client/index.htmlyesVite client build (browser bundle entry)
dist/ssr/main.server.jsyesVite SSR build of the Angular app
dist/analog/public/index.htmlyesNitro public assets (client + prerendered pages)
dist/analog/server/index.mjsyesNitro production server entry
dist/analog/server/chunks/routes/api/native.mjsyesNative Analog API route
dist/analog/server/chunks/routes/api/strata-core.mjsyesStrata experiment route
dist/analog/nitro.jsonyesNitro build metadata

Native Analog server route (/api/native)

ModeStatusBody
production server200{"source":"analog"}
dev server200{"source":"analog"}

Strata metadata through @strata-sc/core only (/api/strata-core)

ModeStatusBody
production server200{"source":"strata-core","definition":{"path":"/hello","routes":[{"method":"GET","path":"/","handler":"hello"}]},"invoked":{"message":"Hello from Strata","marker":"STRATA_ANALOG_SERVER_ONLY_MARKER"}}
dev server200{"source":"strata-core","definition":{"path":"/hello","routes":[{"method":"GET","path":"/","handler":"hello"}]},"invoked":{"message":"Hello from Strata","marker":"STRATA_ANALOG_SERVER_ONLY_MARKER"}}

H3 seam and @strata-sc/h3

Nitro hands its app to server plugins through the public defineNitroPlugin() from nitropack/runtime; NitroApp.h3App and NitroApp.router are part of Nitro's exported NitroApp type. A fixture plugin observed (never modified) what a real production server passes:

{
  "nitroAppKeys": ["captureError", "h3App", "hooks", "localCall", "localFetch", "router"],
  "h3App": {
    "typeofValue": "object",
    "constructorName": "Object",
    "ownKeys": ["handler", "options", "resolve", "stack", "use", "websocket"],
    "hasOn": false,
    "hasUse": true,
    "hasStack": true,
    "hasFetch": false,
    "hasRoutes": false
  },
  "router": {
    "typeofValue": "object",
    "constructorName": "Object",
    "ownKeys": [
      "add",
      "connect",
      "delete",
      "get",
      "handler",
      "head",
      "options",
      "patch",
      "post",
      "put",
      "trace",
      "use"
    ],
    "hasOn": false,
    "hasUse": true,
    "hasStack": false,
    "hasFetch": false,
    "hasRoutes": false
  }
}

registerControllers() in @strata-sc/h3 (packages/h3/src/register-controllers.ts) calls app.on(...): yes. The Nitro h3App has .on: no.

Outcome B. Nitro exposes its H3 through a public plugin hook, but as an H3 v1 App (use/stack) and v1 Router, not an H3 v2 H3 instance. The current @strata-sc/h3 cannot mount directly.

@strata-sc/h3 was not mounted in Analog: the only H3 app the public seam provides is an H3 v1 App, and passing it to a function typed for the H3 v2 H3 class would need an unsafe cast between majors, a fake H3 instance, or a second router — all ruled out for this experiment.

@strata-sc/analog: a Strata controller through the public Nitro router seam

src/server/plugins/strata.ts is a Nitro server plugin that calls registerControllers(nitroApp.router, [UsersController, LifecycleController]) and, separately, registerControllers(nitroApp.router, [GreetingController], { controllerFactory }). None of these controllers is reachable from any file under src/server/routes/**: no file-system route wraps them. The routes below exist only because @strata-sc/analog read their @strata-sc/core metadata and registered them on nitroApp.router.

Controllers are request-scoped: LifecycleController and GreetingController increment an instance field, and each is requested twice in a row per mode. Both answers carry calls: 1, so each request got a new instance. GreetingController receives a plain GreetingService only from the fixture's controllerFactory (Strata's default factory would leave it null).

RouteModeStatusContent-TypeBody
GET /api/strata/usersproduction server200application/json[{"id":"1","name":"Ada"}]
GET /api/strata/usersdev server200application/json[{"id":"1","name":"Ada"}]
GET /api/strata/users/42production server200application/json{"id":"42","name":"Ada"}
GET /api/strata/users/42dev server200application/json{"id":"42","name":"Ada"}
GET /api/strata/lifecycle (1st)production server200application/json{"calls":1}
GET /api/strata/lifecycle (2nd)production server200application/json{"calls":1}
GET /api/strata/greeting (1st)production server200application/json{"greeting":"hello","calls":1,"intercepted":true}
GET /api/strata/greeting (2nd)production server200application/json{"greeting":"hello","calls":1,"intercepted":true}
GET /api/strata/methodsproduction server200application/json{"handler":"list","method":"GET"}
POST /api/strata/methods {"name":"Ada"}production server200application/json{"handler":"create","method":"POST","name":"Ada"}
PUT /api/strata/methods/7production server200application/json{"handler":"replace","method":"PUT","id":"7"}
PATCH /api/strata/methods/42 {"name":"Grace"}production server200application/json{"handler":"update","method":"PATCH","id":"42","name":"Grace"}
DELETE /api/strata/methods/42production server200application/json{"handler":"remove","method":"DELETE","deleted":"42"}
GET /api/strata/lifecycle (1st)dev server200application/json{"calls":1}
GET /api/strata/lifecycle (2nd)dev server200application/json{"calls":1}
GET /api/strata/greeting (1st)dev server200application/json{"greeting":"hello","calls":1,"intercepted":true}
GET /api/strata/greeting (2nd)dev server200application/json{"greeting":"hello","calls":1,"intercepted":true}
GET /api/strata/methodsdev server200application/json{"handler":"list","method":"GET"}
POST /api/strata/methods {"name":"Ada"}dev server200application/json{"handler":"create","method":"POST","name":"Ada"}
PUT /api/strata/methods/7dev server200application/json{"handler":"replace","method":"PUT","id":"7"}
PATCH /api/strata/methods/42 {"name":"Grace"}dev server200application/json{"handler":"update","method":"PATCH","id":"42","name":"Grace"}
DELETE /api/strata/methods/42dev server200application/json{"handler":"remove","method":"DELETE","deleted":"42"}

The native Analog route (/api/native, above) answers in the same run, on the same router.

Experiment (SPEC-003): Angular DI through controllerFactory

Specified by SPEC-003; the source trace, candidate comparison and verdict are in Analog DI feasibility. src/server/plugins/strata-angular-di.ts registers CatalogController with a factory owned by the fixture, not by @strata-sc/analog (which has no Angular dependency). The plugin bootstraps an application injector with Angular's public createApplication() on a platformServer(), as Analog does for its server functions, so @Injectable({ providedIn: 'root' }) CatalogService resolves there once per process. For each request the factory creates a child createEnvironmentInjector() providing STRATA_REQUEST, RequestIdentity and RequestAudit, registers onCleanup(() => requestInjector.destroy()), and builds the controller with runInInjectionContext(requestInjector, () => new Controller()). The controller resolves its dependencies with inject() in field initializers and keeps them across await; it also calls inject() inside its handler, before and after an await, and reports the outcome. No Nitro request/afterResponse/error hook or event.context slot is used (checked on the sources); only the application is destroyed in Nitro's close hook.

Each scenario is bracketed by two reads of /api/strata-angular-di-stats, once each, with no retry; the table shows after − before, except for levels shown as read: injectorsAlive, maxInjectorsAlive and catalogInstances (the providedIn: 'root' service is created lazily by the first request and must stay at one). Overlap is enforced, not assumed: ?meet=<key> holds a handler at a rendezvous that answers met: true only if a second request with the same key reaches it while the first is still suspended, and met: false after 5 s otherwise. The lone request is the negative control.

ModeScenarioResponsesCounter deltaResult
production servertwo requests held at a rendezvous200 {"met":true,"product":{"id":"a","name":"Product a"},"catalogInstance":1,"identity":2,"identityProductId":"a","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false}<br>200 {"met":true,"product":{"id":"b","name":"Product b"},"catalogInstance":1,"identity":1,"identityProductId":"b","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false}{"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
production serverone request alone at a rendezvous (control)200 {"met":false,"product":{"id":"solo","name":"Product solo"},"catalogInstance":1,"identity":3,"identityProductId":"solo","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
production serverhandler throws synchronously500 {"error":true,"message":"Server Error"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
production serverasync handler rejects after an await500 {"error":true,"message":"Server Error"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
production serverauthorized DI routes compose verified principals, interceptors and Standard Schema200 {"product":{"id":"101","name":"Product 101"},"tag":"TRANSFORMED","met":null,"principal":"alpha","identity":7,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"id":102,"count":7,"principal":"beta","identity":6,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}{"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}pass
production server401 and 403 denials run guard cleanup before any interceptor or Angular construction401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>403 {"error":"forbidden"}<br>403 {"error":"forbidden"}{"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":4,"guardCleanups":4,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
production serverinvalid Standard Schema input is safe and destroys the authorized request injector400 {"error":"invalid_request","source":"params"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
production servermalformed, unsupported and oversized JSON failures clean up request injectors400 {"error":"invalid_request","source":"body"}<br>415 {"error":"unsupported_media_type","source":"body"}<br>413 {"error":"payload_too_large","source":"body"}{"injectorsCreated":3,"injectorsDestroyed":3,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":3,"controllersReleased":3,"catalogInstances":1,"guardEntered":3,"guardCleanups":3,"interceptorEvents":6,"interceptorCleanups":6,"controllerConstructions":3,"handlerCalls":3,"cleanupOrderChecks":3,"cleanupOrderFailures":0,"interceptorLiveChecks":6,"interceptorLiveFailures":0}pass
production serverrequest provider override remains local to one child injector200 {"product":{"id":"101","name":"Product 101"},"tag":"X","met":null,"principal":"alpha","identity":13,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"only-this-request","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"102","name":"Product 102"},"tag":"X","met":null,"principal":"beta","identity":12,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}{"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}pass
production servercontroller factory failure runs guard and interceptor cleanup without an injector500 {"error":true,"message":"Server Error"}{"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
production serverprovider factory failure destroys the created request injector500 {"error":true,"message":"Server Error"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
production servercontroller constructor failure destroys its request injector500 {"error":true,"message":"Server Error"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
production serverhandler, interceptor and multiple cleanup failures settle without leaking private errors500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}{"injectorsCreated":5,"injectorsDestroyed":5,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":5,"controllersReleased":5,"catalogInstances":1,"guardEntered":5,"guardCleanups":5,"interceptorEvents":10,"interceptorCleanups":10,"controllerConstructions":5,"handlerCalls":5,"cleanupOrderChecks":5,"cleanupOrderFailures":0,"interceptorLiveChecks":11,"interceptorLiveFailures":0}pass
production serverinterceptor failure before next cleans up without constructing a controller500 {"error":true,"message":"Server Error"}{"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
production servernative Web Response is preserved through interceptors200 native-response-preserved{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
production server24 mixed requests in three overlapping eight-request batches isolate state200 {"product":{"id":"101","name":"Product 101"},"tag":"M0","met":true,"principal":"alpha","identity":22,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"102","name":"Product 102"},"tag":"M1","met":true,"principal":"beta","identity":23,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"103","name":"Product 103"},"tag":"M2","met":true,"principal":"alpha","identity":24,"identityProductId":"103","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"104","name":"Product 104"},"tag":"M3","met":true,"principal":"beta","identity":26,"identityProductId":"104","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"105","name":"Product 105"},"tag":"M4","met":true,"principal":"alpha","identity":25,"identityProductId":"105","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"106","name":"Product 106"},"tag":"M5","met":true,"principal":"beta","identity":27,"identityProductId":"106","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"107","name":"Product 107"},"tag":"M6","met":true,"principal":"alpha","identity":28,"identityProductId":"107","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"108","name":"Product 108"},"tag":"M7","met":true,"principal":"beta","identity":29,"identityProductId":"108","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>400 {"error":"invalid_request","source":"params"}<br>400 {"error":"invalid_request","source":"params"}<br>400 {"error":"invalid_request","source":"params"}<br>400 {"error":"invalid_request","source":"params"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}<br>500 {"error":true,"message":"Server Error"}{"injectorsCreated":20,"injectorsDestroyed":20,"injectorsAlive":0,"maxInjectorsAlive":8,"identitiesDestroyed":20,"controllersReleased":20,"catalogInstances":1,"guardEntered":24,"guardCleanups":24,"interceptorEvents":40,"interceptorCleanups":40,"controllerConstructions":20,"handlerCalls":20,"cleanupOrderChecks":20,"cleanupOrderFailures":0,"interceptorLiveChecks":44,"interceptorLiveFailures":0}pass
dev servertwo requests held at a rendezvous200 {"met":true,"product":{"id":"a","name":"Product a"},"catalogInstance":1,"identity":1,"identityProductId":"a","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false}<br>200 {"met":true,"product":{"id":"b","name":"Product b"},"catalogInstance":1,"identity":2,"identityProductId":"b","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false}{"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
dev serverone request alone at a rendezvous (control)200 {"met":false,"product":{"id":"solo","name":"Product solo"},"catalogInstance":1,"identity":3,"identityProductId":"solo","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
dev serverhandler throws synchronously500 {"error":true,"message":"thrown by request 4"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
dev serverasync handler rejects after an await500 {"error":true,"message":"rejected by request 5"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
dev serverauthorized DI routes compose verified principals, interceptors and Standard Schema200 {"product":{"id":"101","name":"Product 101"},"tag":"TRANSFORMED","met":null,"principal":"alpha","identity":7,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"id":102,"count":7,"principal":"beta","identity":6,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}{"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}pass
dev server401 and 403 denials run guard cleanup before any interceptor or Angular construction401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>403 {"error":"forbidden"}<br>403 {"error":"forbidden"}{"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":4,"guardCleanups":4,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
dev serverinvalid Standard Schema input is safe and destroys the authorized request injector400 {"error":"invalid_request","source":"params"}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
dev servermalformed, unsupported and oversized JSON failures clean up request injectors400 {"error":"invalid_request","source":"body"}<br>415 {"error":"unsupported_media_type","source":"body"}<br>413 {"error":"payload_too_large","source":"body"}{"injectorsCreated":3,"injectorsDestroyed":3,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":3,"controllersReleased":3,"catalogInstances":1,"guardEntered":3,"guardCleanups":3,"interceptorEvents":6,"interceptorCleanups":6,"controllerConstructions":3,"handlerCalls":3,"cleanupOrderChecks":3,"cleanupOrderFailures":0,"interceptorLiveChecks":6,"interceptorLiveFailures":0}pass
dev serverrequest provider override remains local to one child injector200 {"product":{"id":"101","name":"Product 101"},"tag":"X","met":null,"principal":"alpha","identity":12,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"only-this-request","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"102","name":"Product 102"},"tag":"X","met":null,"principal":"beta","identity":13,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}{"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}pass
dev servercontroller factory failure runs guard and interceptor cleanup without an injector500 {"error":true,"message":"Request failed."}{"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
dev serverprovider factory failure destroys the created request injector500 {"error":true,"message":"Request failed."}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
dev servercontroller constructor failure destroys its request injector500 {"error":true,"message":"Request failed."}{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
dev serverhandler, interceptor and multiple cleanup failures settle without leaking private errors500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"3 Strata cleanup callbacks failed."}{"injectorsCreated":5,"injectorsDestroyed":5,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":5,"controllersReleased":5,"catalogInstances":1,"guardEntered":5,"guardCleanups":5,"interceptorEvents":10,"interceptorCleanups":10,"controllerConstructions":5,"handlerCalls":5,"cleanupOrderChecks":5,"cleanupOrderFailures":0,"interceptorLiveChecks":11,"interceptorLiveFailures":0}pass
dev serverinterceptor failure before next cleans up without constructing a controller500 {"error":true,"message":"Request failed."}{"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}pass
dev servernative Web Response is preserved through interceptors200 native-response-preserved{"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}pass
dev server24 mixed requests in three overlapping eight-request batches isolate state200 {"product":{"id":"101","name":"Product 101"},"tag":"M0","met":true,"principal":"alpha","identity":22,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"102","name":"Product 102"},"tag":"M1","met":true,"principal":"beta","identity":24,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"103","name":"Product 103"},"tag":"M2","met":true,"principal":"alpha","identity":23,"identityProductId":"103","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"104","name":"Product 104"},"tag":"M3","met":true,"principal":"beta","identity":25,"identityProductId":"104","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"105","name":"Product 105"},"tag":"M4","met":true,"principal":"alpha","identity":26,"identityProductId":"105","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"106","name":"Product 106"},"tag":"M5","met":true,"principal":"beta","identity":27,"identityProductId":"106","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"107","name":"Product 107"},"tag":"M6","met":true,"principal":"alpha","identity":28,"identityProductId":"107","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>200 {"product":{"id":"108","name":"Product 108"},"tag":"M7","met":true,"principal":"beta","identity":29,"identityProductId":"108","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]}<br>401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>401 {"error":"unauthorized"}<br>400 {"error":"invalid_request","source":"params"}<br>400 {"error":"invalid_request","source":"params"}<br>400 {"error":"invalid_request","source":"params"}<br>400 {"error":"invalid_request","source":"params"}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}<br>500 {"error":true,"message":"Request failed."}{"injectorsCreated":20,"injectorsDestroyed":20,"injectorsAlive":0,"maxInjectorsAlive":8,"identitiesDestroyed":20,"controllersReleased":20,"catalogInstances":1,"guardEntered":24,"guardCleanups":24,"interceptorEvents":40,"interceptorCleanups":40,"controllerConstructions":20,"handlerCalls":20,"cleanupOrderChecks":20,"cleanupOrderFailures":0,"interceptorLiveChecks":44,"interceptorLiveFailures":0}pass

Expected: overlapping requests both answer met: true, share catalogInstance: 1, and get different identity values, each bound to its own product id; the controller and RequestAudit see the same RequestIdentity within a request; the injected STRATA_REQUEST is the handler's argument; inject() in a handler throws NG0203 before and after an await; no injector is destroyed before the handler's last await settles; and every request injector created — on success, synchronous throw or asynchronous rejection — is destroyed, running RequestIdentity.ngOnDestroy() and the controller's DestroyRef callback, before the response arrives. Limits: the application injector is not the injector of an Analog SSR render or of Analog's server functions (no supported seam reaches either), and cleanup covers the controller invocation, not a streamed response body. The experiment's files carry STRATA_ANALOG_ANGULAR_DI_MARKER, scanned in the module-graph section below.

Package boundary. @strata-sc/analog declares:

FieldValue
dependencies{"@standard-schema/spec":"1.1.0","@strata-sc/core":"workspace:*"}
peerDependencies{}
devDependencies{"h3":"^1.15.11","valibot":"^1.5.0","zod":"^4.6.5"}
engines.node>=22

Bare module specifiers in the built package (what a consumer's bundler and tsc must resolve):

Built fileImports
packages/analog/dist/api-boundary.d.ts@strata-sc/core
packages/analog/dist/cleanup-scope.d.tsnone
packages/analog/dist/errors.d.tsnone
packages/analog/dist/http-error.d.tsnone
packages/analog/dist/index.d.tsnone
packages/analog/dist/index.js@strata-sc/core
packages/analog/dist/input-error.d.tsnone
packages/analog/dist/register-controllers.d.ts@standard-schema/spec, @strata-sc/core
packages/analog/dist/request-observation.d.tsnone
packages/analog/dist/responses.d.tsnone
packages/analog/dist/stream-lifecycle.d.tsnone
packages/analog/dist/utils/build-route-path.d.tsnone

The fixture reaches the package only through @strata-sc/analog (its exports entry, built dist).

Type check against Nitro's real types. A generated probe calls registerControllers(nitroApp.router, …) inside defineNitroPlugin and type-checks it against the nitropack Analog resolves: the router is accepted without a cast, and nitroApp.h3App (H3 v1 App) is rejected — a @ts-expect-error negative control that fails if the parameter were loosely typed. Command: pnpm exec tsc -p .strata-typecheck/tsconfig.json (exit 0).

Server/client module graph baseline

STRATA_ANALOG_SERVER_ONLY_MARKER is used only from src/server/strata/hello.controller.ts (imported by Nitro routes). STRATA_ANALOG_CLIENT_CONTROL_MARKER is a positive control that lives in a client page, so a scan that finds it proves the scanner can see client output at all.

OutputServer-only markerClient control marker@strata-sc/core internal symbol
server (dist/analog/server)chunks/routes/api/strata-core.mjschunks/_/index.page-_tgWCWVj.mjschunks/nitro/nitro.mjs
SSR bundle (dist/ssr)noneassets/index.page-_tgWCWVj.jsnone
client (dist/client)noneassets/index.page-TukbXcQ3.jsnone
public (dist/analog/public)noneassets/index.page-TukbXcQ3.js, index.htmlnone

STRATA_ANALOG_REGISTERED_CONTROLLER_MARKER is used only by the controller registered through @strata-sc/analog (src/server/strata/users.controller.ts, imported only by the Nitro plugin). STRATA_ANALOG_CONTROLLER_FACTORY_MARKER is used only by src/server/strata/greeting.controller.ts, registered with a custom controllerFactory:

OutputRegistered-controller markerController-factory markerAngular DI experiment marker@strata-sc/analog (error class name)@strata-sc/h3 (error class name)
server (dist/analog/server)chunks/nitro/nitro.mjschunks/nitro/nitro.mjschunks/nitro/nitro.mjschunks/nitro/nitro.mjsnone
SSR bundle (dist/ssr)nonenonenonenonenone
client (dist/client)nonenonenonenonenone
public (dist/analog/public)nonenonenonenonenone

Expected and observed: server output contains the server-only markers and the adapter; dist/client, dist/analog/public and dist/ssr do not; no @strata-sc/h3 code is in any output. This is only a baseline — nothing here is a Server Component or a guarantee for future code.

Commands

StepCommandExit
Build @strata-sc/corepnpm --filter @strata-sc/core run build0
Build @strata-sc/analogpnpm --filter @strata-sc/analog run build0
Type-check @strata-sc/analog against Nitro's typespnpm exec tsc -p .strata-typecheck/tsconfig.json0
G1 probe build (stock experimentalDecorators: true)pnpm exec vite build --config vite.probe.config.ts1
G2 probe build (experimentalDecorators: false)pnpm exec vite build --config vite.probe.config.ts0
G2 production servernode dist/analog/server/index.mjsstopped by test
G2 dev serverpnpm exec vite --port <port> --strictPort --config vite.probe.config.tsstopped by test
Baseline production buildpnpm --filter @strata-fixtures/analog run build0
Production servernode dist/analog/server/index.mjsstopped by test
Dev serverpnpm exec vite --port <port> --strictPortstopped by test

Checks

CheckResultDetail
Analog's Nitro plugin resolves the same H3 as nitropackpassplugin → 1.15.11, nitropack → 1.15.11
Analog/Nitro run H3 v1 and @strata-sc/h3 runs H3 v2passnitropack → 1.15.11, @strata-sc/h3 → 2.0.1-rc.32
No Nitro 3 (nitro package) in the workspace graphpasslockfile scan
@strata-sc/analog builds (JS + declarations)pass
@strata-sc/analog declares only @strata-sc/core and Standard Schema, with no peerspass{"dependencies":{"@standard-schema/spec":"1.1.0","@strata-sc/core":"workspace:*"}}
@strata-sc/analog does not depend on @strata-sc/h3 (in any dependency field)pass@standard-schema/spec, @strata-sc/core, h3, valibot, zod
The built @strata-sc/analog imports only core and Standard Schema — no h3, nitropack or Analogpass@standard-schema/spec, @strata-sc/core
Public package engines are not raised to the fixture's Node floorpasscore: >=22, h3: >=22, analog: >=22
The fixture imports only the public @strata-sc/analog entry (no deep imports)pass@strata-sc/analog
The fixture has no alias or path into packages/analog sourcepass
The fixture resolves @strata-sc/analog to the workspace package (via its package.json exports)pass/Volumes/WorkStation/projects/Strata/packages/analog vs /Volumes/WorkStation/projects/Strata/packages/analog
The Strata route is registered by the Nitro plugin, not by a file-system route wrapperpassplugin calls registerControllers(nitroApp.router, …)
Nitro's real nitroApp.router type is accepted by registerControllers as-is; nitroApp.h3App is rejectedpass
G2 failure cause: Node's import+node tslib entry is missing from the server outputpasstraced: package.json, tslib.es6.mjs
Analog production build exits 0passexit 0
Client and server artifacts are generatedpass
Built server records the resolved Nitro versionpassnitro.json 2.13.4, resolved 2.13.4
Nitro lowered the consumer's standard decorators (no raw decorator syntax left)passdist/analog/server/chunks/routes/api/strata-core.mjs
The built server bundles H3 v1 (createApp/createRouter) and no H3 v2 H3 classpass{"file":"dist/analog/server/chunks/nitro/nitro.mjs","createApp":true,"createRouter":true,"h3Class":false}
Native Analog route works in productionpass200 {"source":"analog"}
getControllerDefinition() metadata is correct in productionpass200 {"source":"strata-core","definition":{"path":"/hello","routes":[{"method":"GET","path":"/","handler":"hello"}]},"invoked":{"message":"Hello from Strata","marker":"STRATA_ANALOG_SERVER_ONLY_MARKER"}}
GET /api/strata/users (registered by @strata-sc/analog) returns 200 JSON in productionpass200 application/json [{"id":"1","name":"Ada"}]
GET /api/strata/users/:id (dynamic route) returns 200 JSON in productionpass200 application/json {"id":"42","name":"Ada"}
Two GET /api/strata/lifecycle requests each get a new controller ({ calls: 1 }) in productionpass200 {"calls":1} | 200 {"calls":1}
GET /api/strata/greeting uses the custom controllerFactory per request in productionpass200 {"greeting":"hello","calls":1,"intercepted":true} | 200 {"greeting":"hello","calls":1,"intercepted":true}
Angular DI experiment releases request injectors via onCleanup, with no Nitro request-lifecycle hookspassonCleanup() not found
Angular DI controller, services and factory import no Nitro/H3 module or event typepassnone
GET /api/strata/methods reaches its own Strata handler with the right method/params/body in productionpass200 application/json {"handler":"list","method":"GET"}
POST /api/strata/methods {"name":"Ada"} reaches its own Strata handler with the right method/params/body in productionpass200 application/json {"handler":"create","method":"POST","name":"Ada"}
PUT /api/strata/methods/7 reaches its own Strata handler with the right method/params/body in productionpass200 application/json {"handler":"replace","method":"PUT","id":"7"}
PATCH /api/strata/methods/42 {"name":"Grace"} reaches its own Strata handler with the right method/params/body in productionpass200 application/json {"handler":"update","method":"PATCH","id":"42","name":"Grace"}
DELETE /api/strata/methods/42 reaches its own Strata handler with the right method/params/body in productionpass200 application/json {"handler":"remove","method":"DELETE","deleted":"42"}
Standard Schema validation case 1 works in productionpass200 application/json {"params":{"id":42},"query":{"tag":["a","b"]}}
Standard Schema validation case 2 works in productionpass200 application/json {"count":7}
Standard Schema validation case 3 works in productionpass400 application/json; charset=utf-8 {"error":"invalid_request","source":"params"}
24 overlapping mixed valid and invalid validation requests remain isolated in productionpassper-request params, query, transformed body, safe error and private canary checks
JSON body failures return real 400/413/415 no-store responses in productionpassmalformed JSON, text/plain and >1 MiB JSON
24 overlapping synthetic guard requests preserve public, 401, 403 and owner access in productionpassopaque fixture tokens and denial non-disclosure
Inventory HTTP contract and protected mutation behavior work in productionpasssafe errors, validated bodies, 201, patch and bodyless 204
HTTP routing and API boundary contract (JSON 404, 405 + Allow, HEAD, OPTIONS, native routes, 24 overlapping requests) works in productionpassowned /api namespace, native routes not shadowed, pages stay HTML
Angular DI experiment (production): two requests held at a rendezvouspass200 {"met":true,"product":{"id":"a","name":"Product a"},"catalogInstance":1,"identity":2,"identityProductId":"a","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false} | 200 {"met":true,"product":{"id":"b","name":"Product b"},"catalogInstance":1,"identity":1,"identityProductId":"b","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false} delta {"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (production): one request alone at a rendezvous (control)pass200 {"met":false,"product":{"id":"solo","name":"Product solo"},"catalogInstance":1,"identity":3,"identityProductId":"solo","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (production): handler throws synchronouslypass500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (production): async handler rejects after an awaitpass500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (production): authorized DI routes compose verified principals, interceptors and Standard Schemapass200 {"product":{"id":"101","name":"Product 101"},"tag":"TRANSFORMED","met":null,"principal":"alpha","identity":7,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"id":102,"count":7,"principal":"beta","identity":6,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} delta {"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}
Angular DI experiment (production): 401 and 403 denials run guard cleanup before any interceptor or Angular constructionpass401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 403 {"error":"forbidden"} | 403 {"error":"forbidden"} delta {"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":4,"guardCleanups":4,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (production): invalid Standard Schema input is safe and destroys the authorized request injectorpass400 {"error":"invalid_request","source":"params"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (production): malformed, unsupported and oversized JSON failures clean up request injectorspass400 {"error":"invalid_request","source":"body"} | 415 {"error":"unsupported_media_type","source":"body"} | 413 {"error":"payload_too_large","source":"body"} delta {"injectorsCreated":3,"injectorsDestroyed":3,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":3,"controllersReleased":3,"catalogInstances":1,"guardEntered":3,"guardCleanups":3,"interceptorEvents":6,"interceptorCleanups":6,"controllerConstructions":3,"handlerCalls":3,"cleanupOrderChecks":3,"cleanupOrderFailures":0,"interceptorLiveChecks":6,"interceptorLiveFailures":0}
Angular DI experiment (production): request provider override remains local to one child injectorpass200 {"product":{"id":"101","name":"Product 101"},"tag":"X","met":null,"principal":"alpha","identity":13,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"only-this-request","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"102","name":"Product 102"},"tag":"X","met":null,"principal":"beta","identity":12,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} delta {"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}
Angular DI experiment (production): controller factory failure runs guard and interceptor cleanup without an injectorpass500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (production): provider factory failure destroys the created request injectorpass500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (production): controller constructor failure destroys its request injectorpass500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (production): handler, interceptor and multiple cleanup failures settle without leaking private errorspass500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":5,"injectorsDestroyed":5,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":5,"controllersReleased":5,"catalogInstances":1,"guardEntered":5,"guardCleanups":5,"interceptorEvents":10,"interceptorCleanups":10,"controllerConstructions":5,"handlerCalls":5,"cleanupOrderChecks":5,"cleanupOrderFailures":0,"interceptorLiveChecks":11,"interceptorLiveFailures":0}
Angular DI experiment (production): interceptor failure before next cleans up without constructing a controllerpass500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (production): native Web Response is preserved through interceptorspass200 native-response-preserved delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (production): 24 mixed requests in three overlapping eight-request batches isolate statepass200 {"product":{"id":"101","name":"Product 101"},"tag":"M0","met":true,"principal":"alpha","identity":22,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"102","name":"Product 102"},"tag":"M1","met":true,"principal":"beta","identity":23,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"103","name":"Product 103"},"tag":"M2","met":true,"principal":"alpha","identity":24,"identityProductId":"103","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"104","name":"Product 104"},"tag":"M3","met":true,"principal":"beta","identity":26,"identityProductId":"104","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"105","name":"Product 105"},"tag":"M4","met":true,"principal":"alpha","identity":25,"identityProductId":"105","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"106","name":"Product 106"},"tag":"M5","met":true,"principal":"beta","identity":27,"identityProductId":"106","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"107","name":"Product 107"},"tag":"M6","met":true,"principal":"alpha","identity":28,"identityProductId":"107","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"108","name":"Product 108"},"tag":"M7","met":true,"principal":"beta","identity":29,"identityProductId":"108","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 400 {"error":"invalid_request","source":"params"} | 400 {"error":"invalid_request","source":"params"} | 400 {"error":"invalid_request","source":"params"} | 400 {"error":"invalid_request","source":"params"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} | 500 {"error":true,"message":"Server Error"} delta {"injectorsCreated":20,"injectorsDestroyed":20,"injectorsAlive":0,"maxInjectorsAlive":8,"identitiesDestroyed":20,"controllersReleased":20,"catalogInstances":1,"guardEntered":24,"guardCleanups":24,"interceptorEvents":40,"interceptorCleanups":40,"controllerConstructions":20,"handlerCalls":20,"cleanupOrderChecks":20,"cleanupOrderFailures":0,"interceptorLiveChecks":44,"interceptorLiveFailures":0}
Server-only marker is present in server outputpassdist/analog/server
Server-only marker is absent from client outputpass
Server-only marker is absent from public outputpass
Server-only marker is absent from SSR bundle outputpass
Client control marker is found in client output (scanner sanity)passdist/client and dist/analog/public
The @strata-sc/analog-registered controllers' markers are present in server outputpassdist/analog/server
@strata-sc/analog is bundled into the server outputpassdist/analog/server
The registered controllers' markers and @strata-sc/analog are absent from client outputpass
The registered controllers' markers and @strata-sc/analog are absent from public outputpass
The registered controllers' markers and @strata-sc/analog are absent from SSR bundle outputpass
No @strata-sc/h3 code is in any output (the Analog adapter does not use it)pass
@strata-sc/core internals are absent from client outputpassdist/client and dist/analog/public
Native Analog route works in the dev serverpass200 {"source":"analog"}
getControllerDefinition() metadata is correct in the dev serverpass200 {"source":"strata-core","definition":{"path":"/hello","routes":[{"method":"GET","path":"/","handler":"hello"}]},"invoked":{"message":"Hello from Strata","marker":"STRATA_ANALOG_SERVER_ONLY_MARKER"}}
GET /api/strata/users (registered by @strata-sc/analog) returns 200 JSON in the dev serverpass200 application/json [{"id":"1","name":"Ada"}]
GET /api/strata/users/:id (dynamic route) returns 200 JSON in the dev serverpass200 application/json {"id":"42","name":"Ada"}
Two GET /api/strata/lifecycle requests each get a new controller ({ calls: 1 }) in the dev serverpass200 {"calls":1} | 200 {"calls":1}
GET /api/strata/greeting uses the custom controllerFactory per request in the dev serverpass200 {"greeting":"hello","calls":1,"intercepted":true} | 200 {"greeting":"hello","calls":1,"intercepted":true}
GET /api/strata/methods reaches its own Strata handler with the right method/params/body in the dev serverpass200 application/json {"handler":"list","method":"GET"}
POST /api/strata/methods {"name":"Ada"} reaches its own Strata handler with the right method/params/body in the dev serverpass200 application/json {"handler":"create","method":"POST","name":"Ada"}
PUT /api/strata/methods/7 reaches its own Strata handler with the right method/params/body in the dev serverpass200 application/json {"handler":"replace","method":"PUT","id":"7"}
PATCH /api/strata/methods/42 {"name":"Grace"} reaches its own Strata handler with the right method/params/body in the dev serverpass200 application/json {"handler":"update","method":"PATCH","id":"42","name":"Grace"}
DELETE /api/strata/methods/42 reaches its own Strata handler with the right method/params/body in the dev serverpass200 application/json {"handler":"remove","method":"DELETE","deleted":"42"}
Standard Schema validation case 1 works in the dev serverpass200 application/json {"params":{"id":42},"query":{"tag":["a","b"]}}
Standard Schema validation case 2 works in the dev serverpass200 application/json {"count":7}
Standard Schema validation case 3 works in the dev serverpass400 application/json; charset=utf-8 {"error":"invalid_request","source":"params"}
24 overlapping mixed valid and invalid validation requests remain isolated in the dev serverpassper-request params, query, transformed body, safe error and private canary checks
JSON body failures return real 400/413/415 no-store responses in the dev serverpassmalformed JSON, text/plain and >1 MiB JSON
24 overlapping synthetic guard requests preserve public, 401, 403 and owner access in the dev serverpassopaque fixture tokens and denial non-disclosure
Inventory HTTP contract and protected mutation behavior work in the dev serverpasssafe errors, validated bodies, 201, patch and bodyless 204
HTTP routing and API boundary contract (JSON 404, 405 + Allow, HEAD, OPTIONS, native routes, 24 overlapping requests) works in the dev serverpassowned /api namespace, native routes not shadowed, pages stay HTML
Angular DI experiment (the dev server): two requests held at a rendezvouspass200 {"met":true,"product":{"id":"a","name":"Product a"},"catalogInstance":1,"identity":1,"identityProductId":"a","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false} | 200 {"met":true,"product":{"id":"b","name":"Product b"},"catalogInstance":1,"identity":2,"identityProductId":"b","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false} delta {"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): one request alone at a rendezvous (control)pass200 {"met":false,"product":{"id":"solo","name":"Product solo"},"catalogInstance":1,"identity":3,"identityProductId":"solo","auditSharesIdentity":true,"injectedRequestIsArgument":true,"injectInHandler":"NG0203","injectAfterAwait":"NG0203","destroyedBeforeResponse":false} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): handler throws synchronouslypass500 {"error":true,"message":"thrown by request 4"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): async handler rejects after an awaitpass500 {"error":true,"message":"rejected by request 5"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":0,"guardCleanups":0,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): authorized DI routes compose verified principals, interceptors and Standard Schemapass200 {"product":{"id":"101","name":"Product 101"},"tag":"TRANSFORMED","met":null,"principal":"alpha","identity":7,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"id":102,"count":7,"principal":"beta","identity":6,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} delta {"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): 401 and 403 denials run guard cleanup before any interceptor or Angular constructionpass401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 403 {"error":"forbidden"} | 403 {"error":"forbidden"} delta {"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":4,"guardCleanups":4,"interceptorEvents":0,"interceptorCleanups":0,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":0,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): invalid Standard Schema input is safe and destroys the authorized request injectorpass400 {"error":"invalid_request","source":"params"} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): malformed, unsupported and oversized JSON failures clean up request injectorspass400 {"error":"invalid_request","source":"body"} | 415 {"error":"unsupported_media_type","source":"body"} | 413 {"error":"payload_too_large","source":"body"} delta {"injectorsCreated":3,"injectorsDestroyed":3,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":3,"controllersReleased":3,"catalogInstances":1,"guardEntered":3,"guardCleanups":3,"interceptorEvents":6,"interceptorCleanups":6,"controllerConstructions":3,"handlerCalls":3,"cleanupOrderChecks":3,"cleanupOrderFailures":0,"interceptorLiveChecks":6,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): request provider override remains local to one child injectorpass200 {"product":{"id":"101","name":"Product 101"},"tag":"X","met":null,"principal":"alpha","identity":12,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"only-this-request","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"102","name":"Product 102"},"tag":"X","met":null,"principal":"beta","identity":13,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} delta {"injectorsCreated":2,"injectorsDestroyed":2,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":2,"controllersReleased":2,"catalogInstances":1,"guardEntered":2,"guardCleanups":2,"interceptorEvents":4,"interceptorCleanups":4,"controllerConstructions":2,"handlerCalls":2,"cleanupOrderChecks":2,"cleanupOrderFailures":0,"interceptorLiveChecks":4,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): controller factory failure runs guard and interceptor cleanup without an injectorpass500 {"error":true,"message":"Request failed."} delta {"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): provider factory failure destroys the created request injectorpass500 {"error":true,"message":"Request failed."} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): controller constructor failure destroys its request injectorpass500 {"error":true,"message":"Request failed."} delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): handler, interceptor and multiple cleanup failures settle without leaking private errorspass500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"3 Strata cleanup callbacks failed."} delta {"injectorsCreated":5,"injectorsDestroyed":5,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":5,"controllersReleased":5,"catalogInstances":1,"guardEntered":5,"guardCleanups":5,"interceptorEvents":10,"interceptorCleanups":10,"controllerConstructions":5,"handlerCalls":5,"cleanupOrderChecks":5,"cleanupOrderFailures":0,"interceptorLiveChecks":11,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): interceptor failure before next cleans up without constructing a controllerpass500 {"error":true,"message":"Request failed."} delta {"injectorsCreated":0,"injectorsDestroyed":0,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":0,"controllersReleased":0,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":0,"handlerCalls":0,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":0,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): native Web Response is preserved through interceptorspass200 native-response-preserved delta {"injectorsCreated":1,"injectorsDestroyed":1,"injectorsAlive":0,"maxInjectorsAlive":2,"identitiesDestroyed":1,"controllersReleased":1,"catalogInstances":1,"guardEntered":1,"guardCleanups":1,"interceptorEvents":2,"interceptorCleanups":2,"controllerConstructions":1,"handlerCalls":1,"cleanupOrderChecks":1,"cleanupOrderFailures":0,"interceptorLiveChecks":2,"interceptorLiveFailures":0}
Angular DI experiment (the dev server): 24 mixed requests in three overlapping eight-request batches isolate statepass200 {"product":{"id":"101","name":"Product 101"},"tag":"M0","met":true,"principal":"alpha","identity":22,"identityProductId":"101","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"102","name":"Product 102"},"tag":"M1","met":true,"principal":"beta","identity":24,"identityProductId":"102","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"103","name":"Product 103"},"tag":"M2","met":true,"principal":"alpha","identity":23,"identityProductId":"103","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"104","name":"Product 104"},"tag":"M3","met":true,"principal":"beta","identity":25,"identityProductId":"104","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"105","name":"Product 105"},"tag":"M4","met":true,"principal":"alpha","identity":26,"identityProductId":"105","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"106","name":"Product 106"},"tag":"M5","met":true,"principal":"beta","identity":27,"identityProductId":"106","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"107","name":"Product 107"},"tag":"M6","met":true,"principal":"alpha","identity":28,"identityProductId":"107","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 200 {"product":{"id":"108","name":"Product 108"},"tag":"M7","met":true,"principal":"beta","identity":29,"identityProductId":"108","auditSharesIdentity":true,"injectedRequestIsArgument":true,"configuration":"application","destroyedBeforeResponse":false,"interceptorOrder":["timing:before","outcome:before","injector:created","outcome:after","timing:after"]} | 401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 401 {"error":"unauthorized"} | 400 {"error":"invalid_request","source":"params"} | 400 {"error":"invalid_request","source":"params"} | 400 {"error":"invalid_request","source":"params"} | 400 {"error":"invalid_request","source":"params"} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} | 500 {"error":true,"message":"Request failed."} delta {"injectorsCreated":20,"injectorsDestroyed":20,"injectorsAlive":0,"maxInjectorsAlive":8,"identitiesDestroyed":20,"controllersReleased":20,"catalogInstances":1,"guardEntered":24,"guardCleanups":24,"interceptorEvents":40,"interceptorCleanups":40,"controllerConstructions":20,"handlerCalls":20,"cleanupOrderChecks":20,"cleanupOrderFailures":0,"interceptorLiveChecks":44,"interceptorLiveFailures":0}
Arm S-dev matches its recorded classificationpassexpected A, observed A
Arm S-prod matches its recorded classificationpassexpected A, observed A
Arm N-dev matches its recorded classificationpassexpected A, observed A
Arm N-prod matches its recorded classificationpassexpected A, observed A
Arm G1 matches its recorded classificationpassexpected B, observed B
Arm G2-build matches its recorded classificationpassexpected A, observed A
Arm G2-prod matches its recorded classificationpassexpected C, observed C
Arm G2-dev matches its recorded classificationpassexpected A, observed A
The seam is observable through the public Nitro plugin APIpasscaptureError, h3App, hooks, localCall, localFetch, router
The seam has the same shape in dev and productionpasssnapshot comparison
Recorded seam outcome is B (H3 v1 app, no .on; @strata-sc/h3 needs .on)passoutcome B, strataH3RequiresAppOn true

Blockers discovered

  1. H3 major mismatch at the seam. Analog 2.7.2 → nitropack 2.13.4 → H3 v1. The only public H3 handle (nitroApp.h3App) is an H3 v1 App with no .on(). @strata-sc/h3 needs an H3 v2 H3 instance, so it cannot mount directly (Outcome B). Resolved for Analog without touching it: @strata-sc/analog is a sibling adapter on nitroApp.router and does not depend on @strata-sc/h3. @strata-sc/h3 stays an H3 v2-only adapter.

  2. Phantom h3 dependency in @analogjs/vite-plugin-nitro@2.7.2. It imports h3 without declaring it. Under pnpm's default hoisting, in a workspace that also contains @strata-sc/h3, the bare import resolved to H3 v2 and the Vite config failed to load. This repo now declares the H3 major Nitro 2 uses through packageExtensions in pnpm-workspace.yaml (workspace configuration only; no Strata code changed). Recorded failure before that workaround:

    failed to load config from <repo>/apps/analog-fixture/vite.config.ts
    error during build:
    file://<repo>/node_modules/.pnpm/@analogjs+vite-plugin-nitro@2.7.2_…/node_modules/@analogjs/vite-plugin-nitro/src/lib/utils/register-dev-middleware.js:1
    import { createEvent } from 'h3';
             ^^^^^^^^^^^
    SyntaxError: The requested module 'h3' does not provide an export named 'createEvent'
    
  3. Angular pipeline treats consumer decorators as legacy with the stock experimentalDecorators: true (arm G1, class B). Turning it off makes the dev server work but exposes the next item.

  4. Production SSR of Angular-compiled standard decorators fails on tslib (arm G2-prod, class C): TypeScript's standard-decorator lowering imports __esDecorate/__runInitializers from tslib (importHelpers: true); Nitro traces only tslib's module-condition files, so Node's import + node resolution of tslib/modules/index.js fails at runtime. SSR then returns HTTP 200 with an empty router outlet — a silent failure. Not investigated further or fixed here.

  5. Repo-wide Node floor (addressed). @angular/build@22 and create-analog@2.7.2 require Node ^22.22.3 || ^24.15.0 || >=26, and engine-strict=true makes pnpm install fail below that. The root/workspace development floor is now >=22.22.3. The public engines of @strata-sc/core, @strata-sc/h3 and @strata-sc/analog stay >=22: only the Angular fixture needs the higher patch. CI (node-version: 22) resolves the latest 22.x; that it satisfies the floor was not verified.

  6. Unchanged, not attempted: the H3 v2 / crossws declaration blocker from SPEC-001/SPEC-002. The fixture never imports @strata-sc/h3, so it neither triggers nor hides it.

Non-blocking observations from pnpm install: pnpm ignored the install scripts of esbuild, @parcel/watcher, lmdb and msgpackr-extract (builds and servers worked without approving them), and warns that @angular/build wants vitest@^4.0.8 while the workspace root has vitest@5.0.1 (only used by Angular's own unit-test builder, which the fixture does not run).

Other Analog lines (npm metadata only — not installed, not executed)

Line@analogjs/platformHTTP runtime it declares
latest (this fixture)2.7.2nitropack ^2.13.1 → h3 ^1.15.11
beta2.8.0-beta.5nitropack ^2.13.1
alpha3.0.0-alpha.87nitro 3.0.260903-beta and h3 ^2.0.1-rc.31

The alpha line is the only one whose declared runtime is H3 v2 (same major as @strata-sc/h3). Whether that line exposes a compatible H3 app is unverified; this fixture did not run it.

Source: docs/research/analog-integration-baseline.md

Generated by Entwine · Markdown remains the source of truth.