Amended by 0144: every decorator package ships an
Explorer, and the metadata registry lives in @stackra/container.
Context
stackra gen (0041) must find every decorated class (controllers,
handlers, crons, models, resources), including those that come from packages. Scanning every TypeScript file with a parser is
slow and misses runtime registration. Running the app to find them would start databases and side effects. The container
already knows every provider through its modules (0042), and its decorator
metadata lives in its own WeakMap store (0005).
Decision
- Each member declares its root module in
package.json:"stackra": { "module": "<path>" }. stackra genimports that module in Node and runs the container’s scan and plan steps only. It never instantiates a provider. Decorator metadata comes from the container’s store.- ts-morph reads only the request and response types of the handlers that discovery found, and emits wire interfaces from them. No other file is parsed.
- A validation pass fails the build on duplicate paths, a destructive action without a permission, an unversioned integration event (0078), or exposed PII.
Consequences
- A package’s module is discovered the same way as a service’s. No file globbing and no naming convention is needed.
- Module code must be safe to import without starting anything. Side effects belong in providers, which are never instantiated during gen.
- Discovery is only as complete as the module graph: a class not reachable from the root module does not exist for gen.
Enforcement
The validation pass of decision 4 is itself the check, once built. Planned:pnpm validate fails a tier:service or
tier:app member without a stackra.module field. Nothing checks this today.