Skip to content

refactor(global): the spec SDK, the S3 client and the credential libraries load on first use - #303

Merged
rami-hatoum merged 3 commits into
mainfrom
refactor/four-more-loads-happen-on-first-use
Oct 23, 2026
Merged

rami-hatoum merged 3 commits into
mainfrom
refactor/four-more-loads-happen-on-first-use

Conversation

@rami-hatoum

Copy link
Copy Markdown
Contributor

What this changes

Three more loads a server paid at start for things it may never use, measured by a CPU profile of the start, now happen on first use:

  • The workflow specification SDK and the schema validator, 88 ms, 28 ms for Ajv the SDK imports and 14 ms for the validator, the heaviest modules the server loaded: they compile and register when imported, though a document is read only when a workflow is saved or its graph drawn. One module in the coordination capability loads both with the first document read and keeps them.
  • The S3 client, 11 ms, imported whichever store held the content: it loads only when the settings name a bucket, and the location of content moves to an entry of its own so the settings import no client.
  • The credential libraries, google-auth-library through the Vertex provider at 10 ms and the AWS credential chain at 4.5 ms, which four server modules and the Bedrock provider imported statically: one function of the outbound package loads the chain when first asked, and the content store, the KMS custodian, the Parameter Store keeper and Bedrock ask for it beside the adapter each already loads; the Vertex library loads when Vertex is configured.

Measured on the same machine, the median of eleven starts each: 821 ms, 2,636 files and 21.4 MiB on main; 654 ms, 2,307 files and 18.5 MiB after. The first save of a workflow now pays the load, 175 ms against 34 ms; the second save is unchanged. The tool-servers README carries the numbers beside its measure. The plain-language phrasing's formatters were measured too and left as they are: making them lazy only moved a one-time cost the start pays anyway.

Tests

  • Each library is not reached from its package's entry; the server's start reaches none of them.
  • pnpm check passes on each commit, cold, with the PostgreSQL suite running.

rami-hatoum and others added 3 commits October 23, 2026 14:34
…e first document read

The capability imported @openworkflowspec/sdk and @hyperjump/json-schema with its entry:
dsl-validation.ts took buildGraph and Classes from the SDK, and specification-schema.ts its
workflowSchema, the validator, its formats and the setting that asserts them, at module load.
Importing the SDK compiles its 171 validators, the heaviest module the server loaded, so every
server paid for both at start, though a server that reads no workflow document needs neither.

- dsl-libraries.ts is the one place that loads each, a dynamic import kept while the server
  runs: specificationSdk the SDK, and schemaValidator the validator, its formats registered and
  asserted once, as it loads. The schema check awaits both when it compiles, with the first
  document it checks; the graph check awaits the SDK where it builds the graph, which becomes a
  promise inside dslProblems, which already answered one. The JSON of the SDK's package, which
  names the versions of the DSL it reads, still loads with the capability.
- library-entries.test.ts holds that no module the capability's entry imports reaches either.

Measured on 2026-10-23 on one machine of 16 cores, with Node 26.10.0, by a module load hook on
the thread that serves requests, from the start of the process to its ready line, at the median
of 11 starts on SQLite interleaved with main's, at a load average of 5 to 4: 691 ms against
821 ms, 2,414 files and 20.1 MiB against 2,636 and 21.4 MiB. A CPU profile of 7 starts of each,
sampled every 100 us, at a load average of 3, gave the SDK's module 88 ms of main's start, Ajv,
which it imports, 28 ms more, and the validator 14 ms; after, none of them loads. The first save
of a workflow without expressions pays the loads: 175 ms against 34 ms at the median of 9 servers
of each, and 5.2 ms against 4.9 ms for the second.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…name a bucket

The server's settings read CONTENT_STORE_URL with contentLocationOf from the package's entry,
which also exports the client and the store and so reaches @aws-sdk/client-s3 and
@aws-sdk/lib-storage; content-store.ts imported the same entry. Every server loaded the S3
client at start, though one keeps its content in a bucket only when CONTENT_STORE_URL is set.

- contentLocationOf moves to a subpath of its own, @on.auto/object-storage/location, the module
  it is written in, which reaches nothing of the AWS SDK; the entry of the adapter keeps the
  client, the store and the check of the bucket.
- contentStoreOf, the one place that picks the store, answers nothing when the content is kept
  in the ledger, as before, and otherwise an effect that imports the adapter and composes it; the
  ledger's layer awaits it before the bucket is checked, as it awaited the check. The path of the
  ledger's own content stays synchronous.
- location-entry.test.ts and content-entries.test.ts hold that the location's entry reaches no
  S3 client and that the server's start reaches only that entry.

Measured on 2026-10-23 on the same machine, by the same hook, at the median of 11 starts on SQLite
interleaved with the tree of the commit before, at a load average of 5 to 4: 678 ms against
691 ms, within the spread of the starts, 2,388 files and 19.4 MiB against 2,414 and 20.1 MiB.
The CPU profile gave the two clients 11 ms of the start before and none after, and the AWS SDK
with Smithy 7 ms against 17 ms. The AWS credential chain still loads at start, through the
reasoning capability and the server's other clients, until the commit after.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ovider is configured

Every server loaded at start two credential libraries that only some use. credential-sources.ts
imported google-auth-library for GoogleAuth and OAuth2Client, and cloud-providers.ts the AI SDK's
two Vertex providers, which import it too, though only a server with Vertex configured uses it.
model-factories.ts imported awsCredentialChain from @on.auto/outbound/aws, whose module imports
@aws-sdk/credential-providers and @aws-sdk/rds-signer, and so did the server's content store, its
KMS custodian, its Parameter Store keeper and its list of the variables of the libraries, which
took awsCredentialVariables from it, though only Bedrock, a bucket, KMS and Parameter Store use
the chain. The Entra ID path already loads @azure/identity only for Azure without a key.

- vertex-providers.ts holds what needs google-auth-library: the default credential chain, the
  refreshing client and the two Vertex model factories, moved from credential-sources.ts and
  cloud-providers.ts. modelFactories, where the providers are picked, imports it once when Vertex
  is configured, and the AWS chain once when Bedrock is configured with no credential source
  given, and so answers a promise, which makeModelAccess, already an effect, awaits.
- awsCredentialChainOf, in the main entry of @on.auto/outbound, is the one place that loads the
  AWS chain: it imports the aws subpath when it is first asked. The content store, the KMS
  custodian and the Parameter Store keeper ask for it beside the adapter each already loads, the
  Bedrock entries as model access is built, and awsCredentialVariables moves to the main entry,
  beside the variables of the proxy. A server whose ledger is in PostgreSQL still loads the
  subpath with the module of its store, for the signer of the tokens of IAM.
- credential-libraries.test.ts holds that neither entry of the capability reaches
  google-auth-library, the Vertex providers, @on.auto/outbound/aws or @azure/identity;
  aws-credentials.test.ts that the main entry of outbound loads the credential providers of the
  AWS SDK only when the chain is first asked for; and aws-entries.test.ts that neither module the
  server starts with reaches @on.auto/outbound/aws.
- The tool-servers README records the start of the three commits beside its measure.

Measured on 2026-10-23 on the same machine, by the same hook, at the median of 11 starts on SQLite
interleaved with the tree of the commit before, at a load average of 5 to 4: 654 ms against
678 ms, 2,307 files and 18.5 MiB against 2,388 and 19.4 MiB. The CPU profile gave the Google
library and the packages it alone loads 10 ms of the start before, the credential providers
4.5 ms and the RDS signer 1.7 ms, and none of them anything after. Against main, with the two
commits before, 654 ms against 821 ms, and 2,307 files against 2,636.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@rami-hatoum
rami-hatoum merged commit 21197d5 into main Oct 23, 2026
20 checks passed
@rami-hatoum
rami-hatoum deleted the refactor/four-more-loads-happen-on-first-use branch October 23, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant