refactor(core)!: a runtime resolves ports, it does not need them - #88
Merged
Conversation
Two different `needs` in one framework was one too many. di's Module has one — what a composition root supplies it — and the kernel's Runtime had another, meaning the ports it reads back out of the built application context. They never appear in the same object, which is what made the collision easy to misread rather than harmless. The type parameter follows the field: Runtime<Resolves, Info>, RuntimeHost<Resolves>, RunUnit<Resolves>, RuntimeResolvesOf. So does start's gate sentence, now "UNSATISFIED RUNTIME PORTS — the runtime resolves a port the module does not export". Every shipped runtime declares resolves: [], so an application that composes a starter is unaffected; a hand-rolled runtime renames one field. The array is still never read at run time — it exists so Resolves is inferable from the value, which is now said where the field is declared.
There was a problem hiding this comment.
Pull request overview
Refactors @btravstack/core’s Runtime contract to rename needs → resolves, clarifying that a runtime reads ports from the built application context (distinct from di Module.needs) and aligning the type parameter names and gate messaging accordingly.
Changes:
- Rename
Runtime<Needs, Info>→Runtime<Resolves, Info>(andRuntimeHost,RunUnit, and helper types) and updatestart’s gate sentence toUNSATISFIED RUNTIME PORTS. - Update shipped starters and test utilities to declare
resolves: [](and update type tests/specs accordingly). - Update documentation (package
CLAUDE.md, READMEs, and docs site pages) plus add a changeset for the minor bump.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/testing/src/test-runtime.ts | Update test runtime object to resolves: []. |
| packages/temporal/src/temporal-runtime.ts | Update Temporal runtime object to resolves: []. |
| packages/temporal/CLAUDE.md | Docs wording update to match resolves/gate rename. |
| packages/observability/src/test-fixtures.ts | Update hand-rolled runtime example to resolves: [Logger]. |
| packages/http/src/http-runtime.ts | Update HTTP runtime object to resolves: []. |
| packages/http/CLAUDE.md | Docs wording update to match resolves/gate rename. |
| packages/core/src/start.ts | Rename gate/type plumbing from RuntimeNeedsOf → RuntimeResolvesOf and update gate sentence. |
| packages/core/src/start.test-d.ts | Update type-level gate tests to use resolves and new sentence. |
| packages/core/src/start.spec.ts | Update spec runtime object to resolves: []. |
| packages/core/src/runtime.ts | Rename Runtime field/type parameter and helper type to resolves/RuntimeResolvesOf. |
| packages/core/src/docs-examples.test-d.ts | Update compiled doc examples to resolves. |
| packages/core/README.md | Update README example runtime to resolves. |
| packages/core/CLAUDE.md | Update core package docs to use resolves terminology. |
| packages/amqp/src/amqp-runtime.ts | Update AMQP runtime object to resolves: []. |
| packages/amqp/CLAUDE.md | Docs wording update to match resolves/gate rename. |
| docs/typedoc.core.json | Update intentionallyNotExported for renamed helper type. |
| docs/reference/testing.md | Update testing reference docs to resolves. |
| docs/reference/http.md | Update HTTP reference wording to “resolves nothing”. |
| docs/reference/glossary.md | Update glossary entries for gate/runtime shape. |
| docs/reference/di/entry-points.md | Update entry-points doc to renamed gate arm. |
| docs/reference/core/start.md | Update StartGate docs and arm table to RuntimeResolvesOf/UNSATISFIED RUNTIME PORTS. |
| docs/reference/core/runtime.md | Update runtime reference page to resolves. |
| docs/reference/core/exit-codes.md | Update exit-codes page to renamed gate arm. |
| docs/reference/amqp.md | Update AMQP reference wording to “resolves nothing”. |
| docs/index.md | Update landing-page feature text to match rename. |
| docs/how-to/write-a-runtime.md | Update how-to guide’s runtime definitions/examples to resolves. |
| docs/how-to/open-a-per-request-scope.md | Update per-request scope page to renamed gate arm/field. |
| docs/explanation/why-start.md | Update explanation wording (“ports … not exported”). |
| docs/explanation/the-kernel-maps-nothing.md | Update explanation link text to resolves. |
| docs/explanation/starters.md | Update starters explanation to resolves terminology. |
| docs/explanation/one-process-one-runtime.md | Update explanation link text to match rename. |
| docs/explanation/design-decisions.md | Update gate wording to renamed arm. |
| docs/explanation/compile-time-wiring.md | Update compile-time wiring explanation tables/rows to UNSATISFIED RUNTIME PORTS. |
| docs/examples/order-api.md | Update example doc wording to renamed arm/field. |
| CLAUDE.md | Update repo-wide guidance text to resolves terminology. |
| .changeset/runtime-resolves.md | Add minor changeset documenting the rename and gate sentence update. |
Suppressed comments (2)
packages/core/src/start.test-d.ts:64
@ts-expect-errordirective still references the old gate arm and field name (UNSATISFIED RUNTIME NEEDS/ "needs"). After the rename, this comment should match the new diagnostic wording (UNSATISFIED RUNTIME PORTS/ "resolves") so future readers don't chase the wrong concept.
expectTypeOf<
StartGate<Greeting | NeedsClock>
>().toEqualTypeOf<"UNSATISFIED RUNTIME PORTS — the runtime resolves a port the module does not export">();
packages/core/src/start.test-d.ts:64
- These nearby comments still say "needs-free runtime" / "runtime's needs" even though the type parameter and field were renamed to
Resolves/resolves. Updating the wording will keep the type-test file consistent with the new API and gate terminology.
expectTypeOf<
StartGate<Greeting | NeedsClock>
>().toEqualTypeOf<"UNSATISFIED RUNTIME PORTS — the runtime resolves a port the module does not export">();
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
The sweep renamed the identifiers and the gate sentences and stopped there, so a dozen comments and headings still said `needs` about the runtime — including two `@ts-expect-error` directives naming an arm that no longer exists, which is the worst kind of stale: a negative that still passes while documenting the wrong gate. Every runtime-sense `needs` is now `resolves`: start.test-d's directives and runtime names, runtime.ts's own remaining `Needs` mentions, observability's fixture docstring, the three examples' gate files and README, starters.md's heading, and the reference tables. di's `Needs` channel keeps its name everywhere it appears, which is the distinction the rename existed to draw. Audited mechanically afterwards rather than by eye: every surviving `needs` near the word "runtime" is either di's channel, a unit module's, or the English verb.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two different
needsin one framework was one too many.di's
Modulehas aneeds— what a composition root supplies it — and thekernel's
Runtimehad one too, meaning something else entirely: the ports theruntime reads back out of the built application context. They never appear in
the same object, which is exactly what made the collision easy to misread
rather than harmless.
The type parameter follows the field —
Runtime<Resolves, Info>,RuntimeHost<Resolves>,RunUnit<Resolves>,RuntimeResolvesOf— and so doesstart's gate sentence:Blast radius
Small, because every shipped runtime declares
resolves: []. Anapplication that composes
http()/temporal()/amqp()and never writes aruntime by hand is unaffected; a hand-rolled one renames a field.
RuntimeResolvesOfwas never exported frompackages/core/src/index.ts, sothe public surface change is the
Runtimefield and the gate sentence, nothingelse.
While renaming
The field's own comment now says the thing that was true and unwritten: the
array is never read at run time. It exists so
Resolvesis inferable fromthe value, and
start's gate checks it against the module's exports.Gate
All six green from the root:
format --check,lint,typecheck(31/31),knip,test(30/30),build(10/10). Changeset included — minor, all nine.