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