57 lines
3.0 KiB
Markdown
57 lines
3.0 KiB
Markdown
# 0005: Static module manifests and atomic discovery
|
|
|
|
- Status: Superseded
|
|
- Superseded by: [0006](0006-versioned-capabilities-and-compiled-module-runtime.md)
|
|
- 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.
|