Standardised service instantiation - #34
Draft
ErisDS wants to merge 9 commits into
Draft
Conversation
E2E Tests FailedTo view the Playwright test report locally, run: REPORT_DIR=$(mktemp -d) && gh run download 30003783379 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR" |
ErisDS
force-pushed
the
codex/service-instantiation-pattern
branch
from
August 17, 2026 09:30
5752bbb to
cc38a7d
Compare
E2E Tests FailedTo view the Playwright test report locally, run: REPORT_DIR=$(mktemp -d) && gh run download 32015574704 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR" |
no ref Give every converted composition root the same init and service exports so the proposed pattern is predictable and can be generated mechanically.
E2E Tests FailedTo view the Playwright test report locally, run: REPORT_DIR=$(mktemp -d) && gh run download 32017958344 -n playwright-report -D "$REPORT_DIR" && npx playwright show-report "$REPORT_DIR" |
no ref Make every demonstrated root match the documented init and service contract, while deferring Donations access so importing Stripe before boot no longer violates initialization order.
no ref Keep one initialized service instance while preserving runtime configuration changes used by the token endpoint and acceptance tests.
5 tasks
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.
What this demonstrates
This draft applies one service-instantiation contract across eight deliberately different Ghost services:
{init, service}shapeinit()owns runtime wiring, is idempotent, and creates at most one intended runtime instanceserviceis a stable lazy facade with an actionable pre-init failureThe conversions cover wrapper singletons, a test-only factory, a deferred TypeScript export, a static optional instance, eager construction, a handed-onward repository, and an unmemoized per-consumer factory.
Minimal service pattern
Every service has the same public composition-root shape. The root owns the single runtime instance, resolves Ghost dependencies during
init(), and exports a stableservicefacade:Boot owns initialization:
Consumers use the stable facade:
Every composition root exports
{init, service}, even when no other module currently calls the service directly. This gives developers one pattern to learn and gives a future generator one exact shape to create. A later change could add a minimal boot loader that callsinit()while leaving service construction inside each composition root.The facade is not a container, registry, or service locator. It does not choose implementations, store a list of services, calculate boot order, or look services up by name. Service implementations continue to receive typed dependencies through construction.
Implementation notes
lazySingletonfacade that preserves method binding, property access, assignment, prototype behavior, and test stubbing.{init, service}contract without changing when outbound requests are sent.nullresult when initialized without configuration.services/posts/index.js, removed its implementation export, and stopped returning its concrete instance frominit().PostsService,PostsExporter, andPostStatsinstance after confirming they hold configuration dependencies rather than per-request state.Verification
pnpm buildThe complete Ghost Core unit run passed 7,549 tests. Five unrelated tests failed locally: three gift-preview image tests timed out with Fontconfig unavailable, and two automations repository timestamp tests also failed when rerun alone.
This is a draft reference implementation for review. It is expected to change as the service-instantiation contract is discussed.