feat: add module contracts and discovery
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# 0005: Static module manifests and atomic discovery
|
||||
|
||||
- Status: Accepted
|
||||
- Date: 2026-07-12
|
||||
|
||||
## Context
|
||||
|
||||
Ekklesia modules must be installable by placing a package in `modules/` without editing Core or a
|
||||
central registry. Core must validate identity, compatibility, dependencies, capabilities, storage
|
||||
requirements, and entrypoints before it runs module behavior. Importing an executable TypeScript
|
||||
manifest would allow top-level module code to run before validation completed.
|
||||
|
||||
## Decision
|
||||
|
||||
Every module uses one inert, versioned `ekklesia.module.json` manifest. `@ekklesia/contracts` owns
|
||||
the authoritative Zod schema and serializable types. `@ekklesia/module-sdk` re-exports those public
|
||||
contracts and provides `defineModule` for typed programmatic validation without becoming a Core
|
||||
service locator.
|
||||
|
||||
Core scans immediate non-hidden directories under the configured modules directory. Discovery
|
||||
validates all manifests and package metadata, resolves entrypoints without loading them, checks
|
||||
platform and Module SDK compatibility, resolves module and capability dependencies, and produces a
|
||||
deterministic dependency-first order. Any error rejects the entire discovery result with sorted,
|
||||
structured issues; no module server code is partially loaded.
|
||||
|
||||
Storage requirements are declarative. A module may request one or more logical buckets in its
|
||||
manifest, but it cannot create provider clients or select physical bucket names. The later Core
|
||||
storage service will provision deployment-prefixed physical buckets and give the owning module
|
||||
scoped handles. Buckets remain private unless a future explicit storage contract says otherwise.
|
||||
|
||||
## Alternatives
|
||||
|
||||
- Executable `module.ts` manifests were rejected because discovery would cross the code-execution
|
||||
boundary before validation.
|
||||
- Embedding the full manifest in `package.json` was rejected because it couples the platform
|
||||
contract to package-manager metadata and makes the manifest harder to version independently.
|
||||
- A manually maintained import registry was rejected because every module installation would
|
||||
require a central source edit.
|
||||
- Letting modules configure SeaweedFS or S3 clients directly was rejected because Core owns
|
||||
credentials, provider selection, isolation, and lifecycle.
|
||||
|
||||
## Consequences
|
||||
|
||||
JSON manifests do not provide TypeScript inference by themselves, so validation commands and clear
|
||||
path-aware errors are part of the authoring workflow. A JSON Schema can be generated from the
|
||||
authoritative contract later for editor completion.
|
||||
|
||||
Discovery currently proves entrypoint existence but does not import server behavior, execute
|
||||
lifecycle hooks, provision requested buckets, or register routes, jobs, schemas, and migrations.
|
||||
Those operations begin only after a complete valid discovery result in later runtime slices.
|
||||
|
||||
## Migration implications
|
||||
|
||||
The manifest includes `manifestVersion: 1`. Future incompatible shapes require an explicit schema
|
||||
version and migration path rather than silently changing existing module interpretation.
|
||||
@@ -13,3 +13,4 @@ ADRs capture durable choices that affect more than one package or phase.
|
||||
- [0002: pnpm workspace and strict TypeScript](0002-pnpm-workspace-and-typescript.md) — Accepted
|
||||
- [0003: Development infrastructure](0003-development-infrastructure.md) — Accepted
|
||||
- [0004: Replace unmaintained MinIO baseline](0004-replace-unmaintained-minio.md) — Accepted
|
||||
- [0005: Static module manifests and atomic discovery](0005-static-module-manifests.md) — Accepted
|
||||
|
||||
Reference in New Issue
Block a user