docs(01-02): complete layered config services and events plan
- Record six-level compass, optional services and typed festival bus - Document TDD commits and auto-fixed toolchain/singleton issues
This commit is contained in:
173
.planning/phases/01-framework-kernel-foundation/01-02-SUMMARY.md
Normal file
173
.planning/phases/01-framework-kernel-foundation/01-02-SUMMARY.md
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
---
|
||||||
|
phase: 01-framework-kernel-foundation
|
||||||
|
plan: 02
|
||||||
|
subsystem: kernel
|
||||||
|
tags: [go, koanf, config, plugins, events, context, services]
|
||||||
|
|
||||||
|
requires:
|
||||||
|
- phase: 01-framework-kernel-foundation
|
||||||
|
provides: Hello app boot path, party.Activate, compass.Load, HasConfig/HasCommands
|
||||||
|
provides:
|
||||||
|
- Six-level compass config with Set/Persist/Reload
|
||||||
|
- Optional plugin composition via HasPlugin and typed backpack services
|
||||||
|
- Typed festival event bus with Fire/Collect/UntilHandled
|
||||||
|
- towel request-context accessors
|
||||||
|
affects: [01-03, 01-04, 03]
|
||||||
|
|
||||||
|
tech-stack:
|
||||||
|
added:
|
||||||
|
- github.com/knadh/koanf/providers/file v1.2.1
|
||||||
|
- github.com/knadh/koanf/providers/confmap v1.0.1
|
||||||
|
- github.com/knadh/koanf/providers/env/v2 v2.0.1
|
||||||
|
patterns:
|
||||||
|
- Config priority: runtime Set, persisted overrides, SUMMER_ env, env YAML, base YAML, plugin defaults
|
||||||
|
- Optional integration without importing the optional package (HasPlugin + pact interface)
|
||||||
|
- App-owned service registry and event bus; no process-global request state
|
||||||
|
|
||||||
|
key-files:
|
||||||
|
created:
|
||||||
|
- compass/env.go
|
||||||
|
- compass/persist.go
|
||||||
|
- backpack/services.go
|
||||||
|
- festival/bus.go
|
||||||
|
- towel/context.go
|
||||||
|
- examples/hello/plugins/optional/plugin.go
|
||||||
|
modified:
|
||||||
|
- compass/config.go
|
||||||
|
- party/registry.go
|
||||||
|
- backpack/app.go
|
||||||
|
- pact/capabilities.go
|
||||||
|
- examples/hello/plugins/greeter/plugin.go
|
||||||
|
- examples/hello/summer.yaml
|
||||||
|
|
||||||
|
key-decisions:
|
||||||
|
- "Runtime Set lives in a separate koanf tree so Reload drops it and rebuilds disk layers"
|
||||||
|
- "pact.OptionalMessage is the shared service interface; greeter never imports the optional module"
|
||||||
|
- "Collect/UntilHandled read Collectable/Handleable on the event so Listen stays func(ctx, T) error"
|
||||||
|
- "HasPlugin uses the full activated ID set recorded before Register, not the Booted subset"
|
||||||
|
- "Panic recovery names the owner plugin ID and omits event payload (T-01-05)"
|
||||||
|
|
||||||
|
patterns-established:
|
||||||
|
- "Pattern: plugin embed.FS config/config.yaml merged at the bare plugin ID via MergeAt"
|
||||||
|
- "Pattern: SUMMER_ keys split only on __; single underscores stay in the leaf"
|
||||||
|
- "Pattern: Publish in Register, Lookup in Boot so optional services are visible regardless of Boot order"
|
||||||
|
|
||||||
|
requirements-completed: [KERN-01, KERN-02, KERN-03, KERN-05, KERN-06, KERN-07, KERN-08]
|
||||||
|
|
||||||
|
duration: 25min
|
||||||
|
completed: 2026-09-16
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 1 Plan 2: Layered Config, Services and Events Summary
|
||||||
|
|
||||||
|
**Six-level koanf config with Set/Persist/Reload, optional plugin services without a hard import, and typed festival dispatch with context-scoped request state**
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Duration:** 25 min
|
||||||
|
- **Started:** 2026-09-16T11:06:17Z
|
||||||
|
- **Completed:** 2026-09-16T11:31:20Z
|
||||||
|
- **Tasks:** 3
|
||||||
|
- **Files modified:** 40
|
||||||
|
|
||||||
|
## Accomplishments
|
||||||
|
|
||||||
|
- Compass loads plugin defaults, sorted base YAML, env overlays, `SUMMER_` variables (split on `__`), persisted overrides and runtime Set in D-09 order; Persist is atomic with `0600` files; Reload clears Set
|
||||||
|
- `golem15.optional` is a third hello plugin that publishes `pact.OptionalMessage`; greeter uses `HasPlugin` plus typed lookup and boots with or without it
|
||||||
|
- App-owned `festival.Bus` implements Fire (join errors), Collect (later key wins, partial payload) and UntilHandled, recovers panics with owner IDs, and `towel` carries actor/org/collection/locale on `context.Context`
|
||||||
|
|
||||||
|
## Task Commits
|
||||||
|
|
||||||
|
Each task was committed atomically (TDD RED then GREEN):
|
||||||
|
|
||||||
|
1. **Task 1 RED: failing layered config tests** - `255de60` (test)
|
||||||
|
2. **Task 1 GREEN: layered compass config** - `cc44a1f` (feat)
|
||||||
|
3. **Task 2 RED: failing optional service tests** - `5f22918` (test)
|
||||||
|
4. **Task 2 GREEN: optional plugin services and HasPlugin** - `8696973` (feat)
|
||||||
|
5. **Task 3 RED: failing event and context tests** - `36c152f` (test)
|
||||||
|
6. **Task 3 GREEN: typed events with request context** - `a654e96` (feat)
|
||||||
|
|
||||||
|
**Plan metadata:** pending (docs: complete plan)
|
||||||
|
|
||||||
|
## Files Created/Modified
|
||||||
|
|
||||||
|
- `compass/config.go` / `env.go` / `persist.go` - layered load, env mapping, `.env` fill, Set/Persist/Reload
|
||||||
|
- `party/registry.go` - HasConfig merge and SetPlugins before Register
|
||||||
|
- `backpack/app.go` / `services.go` - HasPlugin, typed Publish/Lookup, app-owned Events bus
|
||||||
|
- `pact/capabilities.go` - OptionalMessage plus documented future KERN-03 families
|
||||||
|
- `festival/bus.go` - typed Listen/Fire/Collect/UntilHandled
|
||||||
|
- `towel/context.go` - unexported-key request accessors
|
||||||
|
- `examples/hello/plugins/optional/` - optional plugin module
|
||||||
|
- `examples/hello/plugins/greeter/plugin.go` - optional lookup and hello event demo
|
||||||
|
- `examples/hello/summer.yaml` / `plugins.gen.go` / `go.work` - third plugin wired
|
||||||
|
|
||||||
|
## Decisions Made
|
||||||
|
|
||||||
|
- Keep runtime Set off the disk tree so Reload is a full rebuild plus an empty overlay
|
||||||
|
- Put the optional service interface in `pact`, not in the optional plugin package
|
||||||
|
- Model Collect/UntilHandled as event interfaces (`Collected`, `IsHandled`) so one `Listen[T]` serves all three modes
|
||||||
|
- Record activated plugin IDs on the app before Register so HasPlugin sees not-yet-Booted plugins
|
||||||
|
- Recover panics as `festival: plugin <id> panicked` without event contents
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
### Auto-fixed Issues
|
||||||
|
|
||||||
|
**1. [Rule 2 - Missing Critical] Restore toolchain go1.27.0 after go mod tidy**
|
||||||
|
- **Found during:** Task 1 (provider install)
|
||||||
|
- **Issue:** `go mod tidy` dropped `toolchain go1.27.0` (same as Plan 01)
|
||||||
|
- **Fix:** Re-added the directive on root and example modules
|
||||||
|
- **Files modified:** `go.mod`, example `go.mod` files
|
||||||
|
- **Verification:** files contain `toolchain go1.27.0`
|
||||||
|
- **Committed in:** `cc44a1f` (Task 1 GREEN)
|
||||||
|
|
||||||
|
**2. [Rule 1 - Bug] Greeter extra leaked across Activate on the init singleton**
|
||||||
|
- **Found during:** Task 2 (hello without-optional test)
|
||||||
|
- **Issue:** `party.Register` stores one plugin instance; Boot with optional set `extra`, later Boot without optional left the old string
|
||||||
|
- **Fix:** Clear `extra` at the start of Boot
|
||||||
|
- **Files modified:** `examples/hello/plugins/greeter/plugin.go`
|
||||||
|
- **Verification:** `TestGreeterRunsWithoutOptionalPlugin` passes
|
||||||
|
- **Committed in:** `8696973` (Task 2 GREEN)
|
||||||
|
|
||||||
|
**3. [Rule 1 - Bug] Hello manifest test still expected two plugins**
|
||||||
|
- **Found during:** Task 2 (`go test ./...`)
|
||||||
|
- **Issue:** `internal/build.TestLoadHelloManifest` hard-coded plugin count 2
|
||||||
|
- **Fix:** Expect `golem15.optional` as the third manifest entry
|
||||||
|
- **Files modified:** `internal/build/build_test.go`
|
||||||
|
- **Verification:** `go test ./internal/build` passes
|
||||||
|
- **Committed in:** `8696973` (Task 2 GREEN)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Total deviations:** 3 auto-fixed (1 missing critical, 2 bugs)
|
||||||
|
**Impact on plan:** Required for D-05, correct optional skip, and a green suite. No scope creep.
|
||||||
|
|
||||||
|
## Issues Encountered
|
||||||
|
|
||||||
|
- `go get` of koanf file/env/confmap providers pulled `fsnotify` transitively through the file provider; it is indirect only and unused by compass (no Watch). Plan 03 still owns `summer dev`.
|
||||||
|
|
||||||
|
## Authentication Gates
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
## User Setup Required
|
||||||
|
|
||||||
|
None - no external service configuration required.
|
||||||
|
|
||||||
|
## Next Phase Readiness
|
||||||
|
|
||||||
|
Ready for `01-03-PLAN.md` (watch loop and CLI UX). Config, optional composition, services and events are in place on the hello path. Do not add HTTP/DB/auth here.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- Created files exist on disk (`compass/env.go`, `compass/persist.go`, `backpack/services.go`, `festival/bus.go`, `towel/context.go`, optional plugin)
|
||||||
|
- Commits `255de60`, `cc44a1f`, `5f22918`, `8696973`, `36c152f`, `a654e96` exist
|
||||||
|
- Root and hello `go vet ./...` and `go test ./...` passed
|
||||||
|
- `go test -race ./compass ./party ./backpack ./festival ./towel` passed
|
||||||
|
- `go run . greeter:hello` prints layered config, optional extra, and event results
|
||||||
|
- Greeter source has no import of the optional plugin module
|
||||||
|
- STATE.md and ROADMAP.md were not updated in this worktree
|
||||||
|
|
||||||
|
---
|
||||||
|
*Phase: 01-framework-kernel-foundation*
|
||||||
|
*Completed: 2026-09-16*
|
||||||
Reference in New Issue
Block a user