docs(01): research kernel planning

This commit is contained in:
Jakub Zych
2026-09-16 12:09:13 +02:00
parent 56c342de0b
commit de01194c75
5 changed files with 197 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
# Phase 1: Framework kernel foundation — Research
**Researched:** 2026-09-16
**Domain:** Go 1.27 compiled plugin kernel, layered configuration, CLI and watch loop
**Confidence:** High for documented library behavior; medium for proposed API shapes until the `examples/hello` integration proves them.
<user_constraints>
## User Constraints
The locked decisions are D-01 through D-17 in [01-CONTEXT.md](01-CONTEXT.md). In particular: two binaries and one `bonfire` command kernel; canonical module path `git.golem15.com/golem15/summercms`; root `go.work` plus permanent `examples/hello`; bare plugin-ID config namespaces; the exact six-level config priority; required `Plugin` plus optional capability interfaces; deterministic lifecycle and event dispatch; hand-rolled output; `fsnotify` watch loop. The framework repository must not import Płytarium or grow the Phase 3 HTTP/ORM/auth stack.
The context leaves the exact event and service APIs, file manifest format, and package dependency direction to implementation. Defer model/migration/controller scaffolding, admin config editing, shared-plugin extraction, and all `surf`/`lagoon`/`bouncer` implementation.
</user_constraints>
<architectural_responsibility_map>
## Architectural Responsibility Map
Single-tier CLI and backend framework. `cmd/summer` owns tool entry, generated app `main.go` owns runtime entry, `party` owns plugin ordering, `backpack` owns app-scoped services, `compass` owns configuration, `festival` owns events, and `bonfire` owns commands and terminal output. The generated app binary is the integration boundary.
</architectural_responsibility_map>
<research_summary>
## Summary
Build the first executable path through `examples/hello`: explicit `summer.yaml` manifest → generated `plugins.gen.go` → app main → config load → all plugin Register calls → all Boot calls → a namespaced plugin command. Extend that path with configuration precedence, optional service integration, event dispatch, and `summer dev`; do not build unused framework layers first. The source-of-truth design is the phase context, with project research supplying examples and pitfalls.
`go.work` can develop multiple modules together, but a root `go test ./...` does not by itself prove nested example modules. Plans need separate `go test`/`go vet` checks from `examples/hello` and a built-binary invocation. Go's `toolchain` directive needs a concrete release, so `toolchain go1.27.0` matches the installed `go1.27.0` and fulfills D-05 without an invalid wildcard. The `go`/`toolchain` directive behavior is documented by [Go](https://go.dev/doc/toolchain), and workspace module membership by the [Go workspace tutorial](https://go.dev/doc/tutorial/workspaces).
**Primary recommendation:** Keep every package API driven by a real hello plugin and its CLI path, then verify the kernel with reordered plugin input, config precedence, non-TTY output, generated code stability, and a measured watch rebuild.
</research_summary>
<standard_stack>
## Standard Stack
| Component | Phase 1 choice | Use |
|---|---|---|
| Compiler/workspace | Go 1.27.0, `go.work` | Root framework plus separate hello app/plugin modules. |
| Config | `github.com/knadh/koanf/v2`, file/confmap/env v2 providers, koanf YAML parser | Ordered deep merges, typed section decode, dot paths. |
| CLI | `github.com/spf13/cobra` | One root command constructor shared by tool and app. |
| Terminal | `golang.org/x/term` plus standard library | TTY detection, password prompt, simple widgets. |
| Watch | `github.com/fsnotify/fsnotify` | Observe app workspace directories and rebuild. |
| Tests | `go test`, `go test -race`, `go vet`; `testify` only if helpful | Unit and example integration coverage. |
The context authorizes these dependencies. Resolve exact module tags during implementation and commit `go.sum`; do not use `@latest` in repeatable plan commands. The [koanf docs](https://pkg.go.dev/github.com/knadh/koanf/v2) confirm successive `Load` calls merge into the existing tree. The current [env/v2 provider](https://pkg.go.dev/github.com/knadh/koanf/providers/env/v2) has `Opt{Prefix, TransformFunc, EnvironFunc}` and can inject an environment source in tests. The earlier project STACK.md's unversioned env-provider example is a sketch, not a required import path.
</standard_stack>
<architecture_patterns>
## Architecture Patterns
```text
summer.yaml → summer build → generated imports + app main → go build → hello binary
↓
config → Register all → Boot all
↓
bonfire root → plugin command → Output
summer dev → fsnotify/debounce → same build function → restart hello binary
```
### Package boundaries
- `pact` holds neutral plugin and capability contracts. If `Plugin.Register`/`Boot` take an app type, define a narrow app-facing interface in `pact` or place the contract in `party` so `pact → backpack → pact` cannot occur. `backpack` implements the interface; `party` orchestrates it.
- `backpack.App` owns config, services and event bus per instance. Typed lookup may be a generic method on a concrete type with Go 1.27, or a generic helper; no package-global service state.
- `festival.Bus` uses typed struct event identity, synchronous listeners, priority descending with stable registration order, and a snapshot of listeners at dispatch. Define collision behavior for collect payloads before implementation (recommended: later invoked listener wins for duplicate keys), then test it.
- `party` may have an `init()` registration slice as the sole allowed process-global registry. Copy it into each app, reject duplicate IDs, validate `Requires()` against the complete set, topologically order with deterministic tie-breaking, then run every Register before any Boot. Return missing/cycle errors with plugin IDs.
- `compass` builds a fresh tree on Reload. Load plugin defaults → sorted base section files → sorted env section files → env variables → persisted overrides → runtime Set. Keep runtime overrides separate so Reload clears them; protect live reads/writes with a lock or immutable snapshot swap. Decode YAML under logical `golem15.fonoteka.*` paths consistently with `SUMMER_GOLEM15__FONOTEKA__*`.
- `bonfire` constructs cobra commands with injected `Input` and `Output`, sets writers explicitly and executes with context. Cobra supports [`AddCommand`, `ExecuteContext`, `SetOut`, and `SetErr`](https://pkg.go.dev/github.com/spf13/cobra). One kernel factory avoids separate tool/app wiring.
### Watch loop
`fsnotify` does not recursively watch subdirectories and recommends watching parent directories rather than individual files because editors replace files atomically. Walk the workspace initially, add new directories on Create, ignore generated binaries/`.git`, debounce bursts, terminate/reap the old process, rebuild through the `summer build` function, and start only a successful new binary. Drain both Events and Errors. See the [fsnotify README](https://github.com/fsnotify/fsnotify/blob/main/README.md).
### MVP boundary
The roadmap marks Phase 1 `mvp`, and the generic GSD Walking Skeleton recipe would include DB/UI. That conflicts with the explicit Phase 1 boundary in CONTEXT.md, which excludes ORM, router, and UI until Phase 3. For this phase the real user is a framework developer: the vertical proof is a generated, bootable hello binary with a working plugin command and live rebuild. `SKELETON.md` should record this phase-specific boundary and hand the DB/HTTP/UI slice to Phase 3.
</architecture_patterns>
<common_pitfalls>
## Common Pitfalls
| Risk | Detection and prevention |
|---|---|
| Import cycles from optional capability signatures | Compile the minimal hello plugin before adding more capabilities; keep future adapters out of `pact` imports. |
| Non-deterministic generated imports or lifecycle | Manifest is an ordered list; regenerate idempotently; use explicit tie-breaking and reordered-input test. |
| Env key ambiguity and `.env` clobbering | Split only on `__`, preserve single underscores, lowercase path segments; do not overwrite `os.LookupEnv` values. |
| Config merge semantics hidden by filenames | Sort files, validate duplicate sections and malformed YAML, test all six priority layers including persisted overrides and Reload. |
| Nested modules skipped by root checks | Run checks in both root and `examples/hello`; execute built app binary. |
| Watcher churn or stale process | Test create/rename/write bursts, rebuild failure, restart, cancellation, and measured rebuild latency. |
| Terminal tests hang in CI | Inject streams and terminal capability; test non-TTY tables, progress, spinner and prompts with pipes. [`x/term`](https://pkg.go.dev/golang.org/x/term) supplies terminal detection and password/raw-mode primitives. |
| Phase 1 grows into a generic CMS | Require each kernel API to have a hello consumer or an explicit Phase 3 handoff; defer unused adapters. |
</common_pitfalls>
<validation_architecture>
## Validation Architecture
The phase has no existing Go tests. Execution should create small smoke tests alongside each functional slice and reserve a final, dedicated unit-test plan for complete behavior coverage, per CLAUDE.md. After every implementation task, run `go vet ./... && go test ./...` at the framework root and, after hello exists, `go vet ./... && go test ./...` from `examples/hello`. The last plan adds `go test -race ./...` for both modules and an integration script/test that runs `summer build` and the generated hello binary in a temporary workspace. Avoid tests that require an interactive terminal.
| Requirement | Automated evidence |
|---|---|
| KERN-01 | Table-driven deep-merge, six-layer precedence, env mapping, `.env`, Set/Persist/Reload, typed decode tests. |
| KERN-02/03/05/08 | Reordered lifecycle input, missing/cycle/duplicate ID, optional interface, HasPlugin and typed service lookup tests. |
| KERN-04 | Stable codegen golden test, `plugin:add` workspace/manifest test, hello `go build` and boot smoke. |
| KERN-06/07 | Three dispatch modes, ordering, errors/panics, app isolation, context propagation and race tests. |
| KERN-09 | Temp workspace create/write/rename and restart test, latency line assertion. |
| CLI-01 | Cobra command discovery and output capture, non-TTY widgets/prompts and color policy tests. |
The fast feedback command should take seconds once dependencies are cached. CI can measure actual duration rather than assume a fixed latency threshold. Test a single plugin source change with `summer dev` and record the measured rebuild time; the acceptance criterion asks for a measurement, not an arbitrary pass threshold.
</validation_architecture>
<open_questions>
## Open Questions
1. **Exact optional capability method signatures for Phase 3+** — `HasModels`, `HasRoutes` and peers are named in KERN-03, but their concrete adapters do not exist yet. Prefer contracts that compile without importing future packages and document that signatures may be refined when the first consumer arrives.
2. **Plugin config representation with dotted IDs** — test koanf lookup behavior for a YAML key `golem15.fonoteka` versus nested `golem15: {fonoteka: ...}` before locking the on-disk form. The public logical path and env mapping remain fixed by D-06/D-08.
3. **Dev watch process ownership across platforms** — implement and test Linux first in this environment; keep command execution behind a small abstraction if later platform handling needs adjustment.
</open_questions>
<sources>
## Sources
- Project decisions: [01-CONTEXT.md](01-CONTEXT.md), [ARCHITECTURE.md](../../research/ARCHITECTURE.md), [PITFALLS.md](../../research/PITFALLS.md), [STACK.md](../../research/STACK.md), `../modules/summer-compass/README.md`, `../modules/summer-bonfire/README.md`.
- Primary references: [Go toolchain](https://go.dev/doc/toolchain), [Go workspaces](https://go.dev/doc/tutorial/workspaces), [koanf](https://pkg.go.dev/github.com/knadh/koanf/v2), [koanf env/v2](https://pkg.go.dev/github.com/knadh/koanf/providers/env/v2), [Cobra](https://pkg.go.dev/github.com/spf13/cobra), [fsnotify](https://github.com/fsnotify/fsnotify/blob/main/README.md), [x/term](https://pkg.go.dev/golang.org/x/term).
</sources>
---
*Phase: 01-framework-kernel-foundation*
*Ready for planning: yes*

View File

@@ -0,0 +1,65 @@
---
phase: 01
slug: framework-kernel-foundation
status: draft
nyquist_compliant: false
wave_0_complete: false
created: 2026-09-16
---
# Phase 1 — Validation Strategy
## Test Infrastructure
| Property | Value |
|---|---|
| Framework | `go test` (Go 1.27.0) |
| Config file | No test harness yet; first implementation slice adds Go tests |
| Quick run | `go vet ./... && go test ./...` from repo root, then from `examples/hello` once created |
| Full suite | Both modules: `go vet ./...`, `go test ./...`, `go test -race ./...`; generated binary integration |
| Estimated runtime | Measure after dependencies are cached; no assumed threshold |
## Sampling Rate
- After each implementation task commit, run root `go vet ./... && go test ./...`; run the same from `examples/hello` after it exists.
- After each plan wave, run both module checks plus the relevant built-binary smoke.
- Before verify-work, run race tests in both modules and an end-to-end `summer build`/hello invocation.
- Record actual feedback latency and single-plugin rebuild latency; no fixed performance promise has been set.
## Per-Requirement Verification Map
| Requirement | Test type | Automated command or assertion | Initial status |
|---|---|---|---|
| KERN-01 | unit + integration | Config precedence and typed decode tests; hello binary prints env-overlay value | Pending |
| KERN-02 | unit + integration | Reordered Register/Boot trace, missing dependency, cycle and duplicate tests | Pending |
| KERN-03 | compile + unit | Hello plugins satisfy optional interfaces; type-assertion discovery | Pending |
| KERN-04 | integration | Stable codegen, `plugin:add`, `go.work`, built hello app boot | Pending |
| KERN-05 | unit | Absent optional plugin returns false; present service lookup returns typed value | Pending |
| KERN-06 | unit + race | Three dispatch modes, priority, stable ties, errors and panic recovery | Pending |
| KERN-07 | unit + race | Two app contexts remain isolated; request values passed only via `context.Context` | Pending |
| KERN-08 | unit | Interface service publish and typed lookup `(value, ok)` | Pending |
| KERN-09 | integration | Temp app source edit triggers one debounced rebuild and restart, latency line captured | Pending |
| CLI-01 | unit + integration | Plugin command discovery, injected output, non-TTY spinner/progress/table/prompt behavior | Pending |
## Wave 0 Requirements
- [ ] First implementation slice creates `examples/hello`, its `go.mod`, and a root `go.work` that names every example module.
- [ ] First implementation slice adds smoke tests for generated app boot and the initial plugin command.
- [ ] Final plan expands unit coverage; it does not substitute for executable checks during earlier work.
## Manual-Only Verifications
| Behavior | Requirement | Why manual | Instructions |
|---|---|---|---|
| Interactive terminal rendering | CLI-01 | Terminal appearance varies by terminal emulator | Run hello command in a TTY; inspect spinner/progress/table and prompts. Automated non-TTY assertions remain required. |
| Rebuild feel | KERN-09 | Human experience complements measured latency | Edit one hello plugin file under `summer dev`; observe restart and printed elapsed time. |
## Validation Sign-Off
- [ ] Every plan task has an automated verification or an explicit Wave 0 dependency.
- [ ] No three consecutive implementation tasks lack automated feedback.
- [ ] Root and nested example modules both run `go vet`, tests and race tests.
- [ ] No watch-mode flags in CI commands.
- [ ] Set `nyquist_compliant: true` after plan-task mapping is complete.
**Approval:** pending plan verification

View File

@@ -1,5 +1,7 @@
# Architecture Research
**Phase 1 correction (2026-09-16):** The canonical Go module is `git.golem15.com/golem15/summercms`; the framework tool lives in this repository, while generated app `main.go` and `plugins.gen.go` live in each app. Phase 1 CONTEXT.md D-01, D-02 and D-04 supersede older `github.com/golem15/summercms` and app-owned `cmd/summer` sketches below.
**Domain:** Go CMF (WinterCMS/Laravel-shaped), headless-first, compiled-plugin model, v1 = Płytarium port
**Researched:** 2026-09-16
**Confidence:** HIGH for plugin-registration mechanics (verified against Caddy/xcaddy and PocketBase current docs) and for request-lifecycle mapping (grounded directly in the real `fonoteka` `Plugin.php`/`routes.php`); MEDIUM for the cross-plugin schema-extension pattern and the framework/app repo split (design recommendation, not yet validated by a build)

View File

@@ -1,5 +1,7 @@
# Stack Research
**Phase 1 correction (2026-09-16):** Plugin config uses bare IDs such as `golem15.fonoteka.*` (not `plugins.<name>.*`), and `summer dev` uses built-in `fsnotify` watching (not an external air install). Phase 1 CONTEXT.md D-06 and D-16 supersede the earlier sketches below.
**Domain:** Go 1.27 backend framework (WinterCMS/Laravel-shaped CMF), headless-first, compiled plugins, porting a PHP backend (Płytarium) to Go
**Researched:** 2026-09-16
**Confidence:** HIGH for versions and maintenance status (checked via pkg.go.dev, GitHub, official docs this session); MEDIUM for architectural recommendations that require judgment calls (migration tool choice, OpenAPI approach, config format)

View File

@@ -6,6 +6,8 @@ source: Research pass during the opening exploration session. Stars and last-pus
# Go ecosystem viability report (WinterCMS -> Go)
**Phase 1 correction (2026-09-16):** The watch loop is built into `summer dev` with `fsnotify`; the external air/reflex suggestion below is superseded by Phase 1 CONTEXT.md D-16.
Verdict: the "Go is closer to PHP's richness" bet holds for every concern except the plugin model, and that has a proven answer (section 2).
## 1. Ecosystem coverage