feat(mcp): derive env vars from the framework's real struct tags (#3)
Minor to v1.1.0. Make the whole environment-variable surface derive from the
indexed component-config tags instead of a hand-maintained list that drifts.
Also folds in the scaffold-symbol fixes staged as v1.0.1 (never tagged); the
generated scaffold compiles clean against einherjar v1.0.0.
internal/envspec (new):
- Parse index struct tags into env vars {name, module, struct, field, required,
default}. One source of truth: ParseTag, ForModule, FindStruct, All, KnownNames.
internal/tools:
- get_config_env: list the real env vars a component config reads (or all).
- check_env: flag unknown EINHERJAR_* names, required vars missing for the
composed modules, and dead vars (set for an uncomposed module).
- get_scaffold: .env.example is now DERIVED from the index — required vars
uncommented with a dev value, defaulted vars commented with their default.
The scaffold now composes logz.Config (Log logz.Config) so EINHERJAR_LOG_*
are live and documented, not hardcoded/ignored (log format is env-driven).
- validate_snippet: inject the real env-var name set into the rules package.
internal/index/builtins (wire conventions):
- Route the incremental "compose a component later" flow to get_config_env /
check_env; distinguish framework EINHERJAR_* from app-owned APP_* (JWT).
- Compose logz.Config in the config + Run() examples, to match the scaffold.
internal/rules:
- config.unknown-env-var (twelfth rule): reject an env:"EINHERJAR_*" struct tag
the framework doesn't declare. No-op until the server injects the name set, so
it never fires on incomplete knowledge.
Fixed (was v1.0.1): scaffold health hook + wire builtin used logz.Logger (real:
contracts/logging.Logger) and postgres.Component (hooks take Provider); env tags
were EINHERJAR_SERVER_ADDR / EINHERJAR_PG_DATABASE (real: _HOST/_PORT / _PG_NAME).
Tests: envspec unit tests; env tools against the real data/index.json; the rule.
Verified by generating the scaffold, building it against local einherjar v1.0.0
(exit 0), and runtime-loading the composed logz.Config (EINHERJAR_LOG_LEVEL=DEBUG
-> slog.LevelDebug, EINHERJAR_LOG_JSON=true). Version bumped to v1.1.0 (badge +
serverVersion). No dependency changes.
Reviewed-on: #3
Co-authored-by: Rene Nochebuena Guerrero <rene@nochebuena.dev>
Co-committed-by: Rene Nochebuena Guerrero <rene@nochebuena.dev>
This commit was merged in pull request #3.
This commit is contained in:
@@ -6,6 +6,56 @@ This module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html
|
||||
|
||||
---
|
||||
|
||||
## [1.1.0] — 2026-08-07
|
||||
|
||||
Minor release. The env-var story is now **derived from the framework's real struct tags** end
|
||||
to end: a tool to read the truth, `.env.example` generated from it, and a rule that rejects
|
||||
invented names. Also folds in the scaffold-symbol fixes that were staged as v1.0.1 (never
|
||||
tagged separately). The generated scaffold compiles clean against einherjar v1.0.0.
|
||||
|
||||
### Added
|
||||
|
||||
- **`get_config_env` tool.** Lists the real environment variables a component config reads —
|
||||
name, declaring module/struct/field, `required`, and default — parsed from the indexed
|
||||
struct tags (`internal/envspec`). The single source of truth for which `EINHERJAR_*` vars
|
||||
exist; no hand-maintained list to drift.
|
||||
- **`check_env` tool.** Checks a `.env` / `.env.example` against the framework: flags
|
||||
`EINHERJAR_*` names that don't exist (e.g. `EINHERJAR_PG_DATABASE`), required vars missing
|
||||
for the modules an app composes, and vars set for a module it does not compose (dead vars,
|
||||
the way `EINHERJAR_SERVER_CORS_ORIGINS` is inert unless you compose `web.Config`).
|
||||
- **`config.unknown-env-var` rule** (now twelve). `validate_snippet` rejects any struct field
|
||||
tagged `env:"EINHERJAR_*"` whose name the framework does not declare — the exact class of
|
||||
drift that shipped `EINHERJAR_PG_DATABASE` / `_SERVER_ADDR`. The valid-name set is injected
|
||||
from the index at startup, so the rule can never drift from the real tags.
|
||||
|
||||
### Changed
|
||||
|
||||
- **`get_scaffold` now derives `.env.example` from the index** instead of a hand-written
|
||||
string. Required vars (no default) are emitted uncommented with a runnable dev value;
|
||||
defaulted vars are emitted commented, documenting the framework default. Names and defaults
|
||||
can no longer drift from the modules the scaffold composes (`core/logz` + `web/server` +
|
||||
`db-postgres`).
|
||||
- **The scaffold composes `logz.Config`** instead of hard-coding the logger, so
|
||||
`EINHERJAR_LOG_LEVEL` / `_JSON` are live and documented rather than silently ignored.
|
||||
Verified end to end: `env.Parse` loads `slog.Level` from `EINHERJAR_LOG_LEVEL`. (Log format
|
||||
is now env-driven; set `EINHERJAR_LOG_JSON=true` in production.)
|
||||
- **The `wire` builtin routes the incremental flow to the new tools.** Composing a component
|
||||
later now points at `get_config_env("<module>")` for its exact vars and `check_env` to
|
||||
confirm `.env.example` is complete — and spells out the split between framework `EINHERJAR_*`
|
||||
(discoverable, name-checked) and app-owned `APP_*` (your discipline).
|
||||
|
||||
### Fixed
|
||||
|
||||
- **`logz.Logger` → `logging.Logger`.** The logger interface is `contracts/logging.Logger`;
|
||||
`logz.New` returns it. The scaffold's health hook and the `wire` builtin's `withUsers`
|
||||
example typed loggers as the non-existent `logz.Logger`.
|
||||
- **`postgres.Component` → `postgres.Provider`** in hook signatures. `postgres.New` returns a
|
||||
`Component` (a lifecycle component that embeds `Provider`); hooks and `NewUnitOfWork` take a
|
||||
`Provider`.
|
||||
- **The real env tags throughout:** `EINHERJAR_SERVER_ADDR` → `EINHERJAR_SERVER_HOST` +
|
||||
`_PORT`, and `EINHERJAR_PG_DATABASE` → `EINHERJAR_PG_NAME` (plus `EINHERJAR_PG_SSL_MODE`).
|
||||
- The scaffold's minimal health hook no longer takes unused `logger`/`db` parameters.
|
||||
|
||||
## [1.0.0] — 2026-08-07
|
||||
|
||||
The MCP reaches **v1.0.0**, aligned with the v1.0.0 framework. The headline is the
|
||||
|
||||
Reference in New Issue
Block a user