Files
summercms/.planning/phases/01-framework-kernel-foundation/01-02-SUMMARY.md
Jakub Zych 6d1b1ec689 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
2026-09-16 13:32:33 +02:00

7.6 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
01-framework-kernel-foundation 02 kernel
go
koanf
config
plugins
events
context
services
phase provides
01-framework-kernel-foundation Hello app boot path, party.Activate, compass.Load, HasConfig/HasCommands
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
01-03
01-04
03
added patterns
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
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
created modified
compass/env.go
compass/persist.go
backpack/services.go
festival/bus.go
towel/context.go
examples/hello/plugins/optional/plugin.go
compass/config.go
party/registry.go
backpack/app.go
pact/capabilities.go
examples/hello/plugins/greeter/plugin.go
examples/hello/summer.yaml
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)
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
KERN-01
KERN-02
KERN-03
KERN-05
KERN-06
KERN-07
KERN-08
25min 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