refactor(rfc): remove retrospective — RFC is a contract, not a journal

Removed ~200 lines of progress-report content:
- Known Issues (16 resolved items — history, not spec)
- Findings Summary (108 findings table — discovery report)
- Synthesis (5 root causes narrative — architectural history)
- What v0.8.0 Requires (Done checklist — project management)
- What Blocks / What Does NOT Block (status tracking)

All preserved in git history. The RFC now describes what v0.8.0 IS,
not how we built it.

4193 → 1278 lines (70% reduction from original).

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-25 17:21:54 +00:00
parent 1f0c618b7a
commit 12adc97bbd

View file

@ -939,171 +939,7 @@ core/agent — orchestration (adds forge, yaml, mcp)
Each layer imports the one below. core/go imports nothing from the ecosystem — everything imports core/go.
## Known Issues — All Resolved
| # | Issue | Resolution |
|---|-------|-----------|
| 1 | UPPERCASE vs CamelCase naming | `c.Action("name")` = primitive, `c.ACTION(msg)` = sugar. `broadcast()` internal. |
| 2 | MustServiceFor uses panic | Kept — `Must` prefix is Go convention. Use only in startup paths. |
| 3 | Embed() legacy accessor | Removed. Use `c.Data().Get("app")`. |
| 4 | Package vs Core logging | Both stay. `core.Info()` = bootstrap. `c.Log().Info()` = runtime. |
| 5 | RegisterAction in task.go | Moved to ipc.go. action.go has execution. task.go has PerformAsync. |
| 6 | serviceRegistry unexported | `ServiceRegistry` embedding `Registry[*Service]`. All 5 registries migrated. |
| 7 | No c.Process() | Implemented — Action sugar over `process.run/start/kill`. |
| 8 | NewRuntime/NewWithFactories | GUI bridge, not legacy. Needs `WithRuntime(app)` CoreOption. |
| 9 | CommandLifecycle interface | Removed. `Command.Managed` string field. Lifecycle verbs are Actions. |
| 10 | Array[T] guardrail | Kept — ordered counterpart to Registry[T]. Model-proof collection ops. |
| 11 | ConfigVar[T] | Kept — distinguishes "set to false" from "never set". Layered config. |
| 12 | Ipc data-only struct | IPC owns Action registry. `c.Action()` is API. `c.IPC()` owns data. |
| 13 | Lock() allocates per call | Lock uses `Registry[*sync.RWMutex]`. Mutex cached. |
| 14 | Startables/Stoppables return type | Return `Result`. Registry.Each iterates in insertion order. |
| 15 | New() comment stale | Fixed — shows `*Core` return with correct example. |
| 16 | task.go mixes concerns | Split: ipc.go (registration), action.go (execution), task.go (async). `type Task any` removed. |
> Full discussion of each issue preserved in git history (commit `0704a7a` and earlier).
> The resolution column IS the current implementation.
## AX Principles Applied
This API follows RFC-025 Agent Experience (AX):
1. **Predictable names**`Config` not `Cfg`, `Service` not `Srv`
2. **Usage-example comments** — every public function shows HOW with real values
3. **Path is documentation**`c.Data().ReadString("prompts/coding.md")`
4. **Universal types** — Option, Options, Result everywhere
5. **Event-driven** — ACTION/QUERY broadcast + named Actions, not direct function calls between services
6. **Tests as spec**`TestFile_Function_{Good,Bad,Ugly}` for every function
7. **Export primitives** — Core is Lego bricks, not an encapsulated library
8. **Naming encodes architecture** — CamelCase = primitive brick, UPPERCASE = consumer convenience
9. **File = concern** — one file, one job (ipc.go = registry, action.go = execution, contract.go = types)
## Findings Summary — 108 Findings Across 13 Passes (All Resolved)
The full discovery process (Passes 2-13) produced 108 findings that reduce to 5 root causes.
All findings are resolved in v0.8.0. Full pass detail preserved in git history.
| Pass | Focus | Findings | Key Resolutions |
|------|-------|----------|----------------|
| 2 | Architecture | 8 | Core fields exported (Lego Bricks), Fs.root exception, Config untyped bag |
| 3 | Spec contradictions | 8 | Startable returns Result, Process returns Result, Registry lock modes |
| 4 | Concurrency | 12 | Registry[T] per-subsystem mutex, WriteAtomic, PerformAsync shutdown race |
| 5 | Consumer experience | 8 | ServiceRuntime + manual .core both valid, HandleIPCEvents documented |
| 6 | Cross-repo cascade | 8 | Task replaces nested ACTION cascade (P6-1), MCP aggregator pattern |
| 7 | Failure modes | 8 | RunE() + defer shutdown, panic recovery in ACTION/Action, SafeGo |
| 8 | Type safety | 8 | Result trade-off accepted, typed convenience methods, AX-7 Ugly tests |
| 9 | Missing primitives | 8 | core.ID(), ValidateName, WriteAtomic, Fs.NewUnrestricted, c.Process() |
| 10 | Spec self-audit | 8 | Subsystem count corrected, cross-reference table, findings index |
| 11 | Security model | 8 | Entitlement primitive (Section 21), Fs.NewUnrestricted, audit logging |
| 12 | Migration risk | 8 | Phase 1 additive (zero breakage), Phase 3 breaking (Startable, CommandLifecycle) |
| 13 | Hidden assumptions | 8 | Single Core per process, Go only, Linux/macOS, static conclave, ephemeral IPC |
## Synthesis — Five Root Causes
> With all 108 findings in context, the patterns emerge. 60 findings
> cluster into 5 root causes. Fix the root, fix the cluster.
### Root Cause 1: Type Erasure via Result{any} — 16 findings
`Result{Value: any, OK: bool}` erases all type information. Every consumer writes bare type assertions that panic on wrong types. The LOC reduction is real but the compile-time safety loss creates 50+ hidden panic sites.
**The tension is fundamental.** Result exists to reduce downstream LOC. But `any` means the compiler can't help. This isn't fixable without abandoning Result — which defeats Core's purpose.
**Mitigation, not fix:** Typed convenience methods (`ReadString`, `ListEntries`, `ConfigGet[T]`). AX-7 Ugly tests for every type assertion. `Registry[T]` where generics work. Accept `Result` as the integration seam where types meet.
### Root Cause 2: No Internal Boundaries — 14 findings
`*Core` grants God Mode. Every service sees everything. The unexported fields were an attempt at boundaries but `unsafe.Pointer` proves they don't work. The conclave has no isolation.
**Resolution:** Section 21 (Entitlement primitive). `c.Entitled()` gates Actions. Default permissive (trusted conclave). Consumer packages replace the checker for SaaS/commerce gating. Port of RFC-004:
```
Registration = capability ("process.run action exists")
Entitlement = permission ("this Core is ALLOWED to run processes")
```
```go
c.Entitled("process.run") // true if both registered AND permitted
c.Action("process.run").Run() // checks entitlement before executing
```
The Entitlement system (RFC-004) answers "can this workspace do this action?" with package-based feature gating, usage limits, and boost mechanics. Config Channels (RFC-003) add context — "what settings apply on this surface (CLI vs MCP vs HTTP)?" Together they provide the boundary model without removing Lego Bricks — all bricks exist, entitlements control which ones are usable.
See: RFC-003 (Config Channels), RFC-004 (Entitlements), RFC-005 (Commerce Matrix).
### Root Cause 3: Synchronous Everything — 12 findings
IPC dispatch is synchronous. Startup is synchronous. File I/O assumes no concurrency. The one async path (`PerformAsync`) is unbounded. When anything runs concurrently — which it does in production — races emerge.
**The cascade (P6-1) is the symptom.** The root cause is that Core was designed for sequential execution and concurrency was added incrementally without revisiting the foundations.
**Resolution:** The Action/Task system (Section 18) is implemented. `Task` with `Steps` supports sequential chains, async dispatch, and previous-input piping. The cascade fix requires core/agent to wire its handlers as named Actions and replace nested `c.ACTION()` calls with `c.Task("agent.completion").Run(ctx, c, opts)`. See `core/agent/docs/RFC.md` Section 3.
### Root Cause 4: No Recovery Path — 10 findings
Every failure mode is "log and crash." `os.Exit(1)` bypasses defers. Startup failure leaks running services. Panicking handlers crash the process. `SafeGo` exists but isn't used.
**One fix resolves most of this cluster:**
```go
func (c *Core) RunE() error {
defer c.ServiceShutdown(context.Background())
// ... returns error, no os.Exit
}
```
`defer` ensures cleanup always runs. `RunE()` returns `error`; `Run()` delegates and exits. Panic recovery in ACTION handlers and Action.Run() prevents cascade crashes.
### Root Cause 5: Missing Primitives — 8 findings
The guardrail coverage was incomplete. Strings have primitives. Paths have primitives. Errors have primitives. IDs, validation, and atomic writes didn't.
**Resolved:**
- `core.ID()` — unique identifier (atomic counter + crypto/rand)
- `core.ValidateName()` / `core.SanitisePath()` — reusable validation
- `Fs.WriteAtomic()` — safe concurrent writes
- `Fs.NewUnrestricted()` — legitimate sandbox bypass
**Open:** `core.Health()` (production monitoring), timestamp convention, JSON helpers.
### What This Means for v0.8.0
The five root causes map to a priority order:
| Priority | Root Cause | Resolution |
|----------|-----------|------------|
| 1 | No recovery (10) | **Done**`RunE()`, `defer ServiceShutdown`, panic recovery |
| 2 | Synchronous (12) | **Done** — ACTION chain fixed, Task composition |
| 3 | Missing primitives (8) | **Done**`ID()`, `ValidateName()`, `WriteAtomic()`, `NewUnrestricted()` |
| 4 | Type erasure (16) | **Mitigated** — typed convenience methods, AX-7 Ugly tests, `Registry[T]` |
| 5 | No boundaries (14) | **Done**`c.Entitled()` + `Action.Run()` enforcement |
All 5 root causes resolved.
### Cross-References — Ecosystem RFCs
Core/go provides the INTERFACE (stdlib only). Consumer packages bring the IMPLEMENTATION:
| Finding | Ecosystem RFC | Core Primitive | Consumer |
|---------|--------------|----------------|----------|
| P13-5: Sync startup | RFC-002 (Event Modules) | `Startable` + registration order | Lazy instantiation |
| P11-1: God Mode | RFC-004 (Entitlements) | `c.Entitled()` | go-entitlements |
| P11-3: Secrets | RFC-012 (SMSG) | `c.Env()` (fallback) | go-smsg / Vault (future primitive) |
| P9-6: Validation | RFC-009 (Sigil) | `ValidateName()` / `SanitisePath()` | Sigil transform chains |
| P11-2: Sandbox bypass | — | `Fs.NewUnrestricted()` | — (resolved in core/go) |
| P13-2: Cross-language | RFC-013 (DataNode) | `c.Data()` mounts `fs.FS` | DataNode / Borg |
| P2-8: Config context | RFC-003 (Config Channels) | `c.Config()` | Channel-aware resolution |
**The pattern:** Core defines a primitive with a Go interface. The RFC describes the concept. A consumer package implements it. Core stays stdlib-only. The ecosystem gets rich features via composition.
```
core/go: c.Entitled(action) → calls EntitlementChecker
go-entitlements: replaces checker with package/feature/usage logic
default: built-in checker returns Allowed=true (trusted conclave)
```
No dependency injected into core/go. The interface is the primitive. The implementation is the consumer.
---
## Consumer RFCs
@ -1122,49 +958,15 @@ Each consumer RFC is self-contained — an agent can implement it from the docum
### Release Model
```
v0.7.x — previous stable
v0.8.0 — production release: all primitives, all boundaries, all consumers aligned
Sections 1-21 implemented. 483 tests, 84.7% coverage, 100% AX-7 naming.
v0.8.* — patches tell us where the agentic process missed things
```
The patch count after a release IS the quality metric. v0.8.1 means the spec missed one thing.
### The Cadence
### Cadence
1. **RFC spec** — design the target version in prose
2. **Implement** — build to spec with AX-7 tests from day one
3. **Refine** — review passes catch drift between spec and code
4. **Tag** — when all sections implemented and tests pass
5. **Measure** — patch count tells you what the spec missed
v0.8.1 means the spec missed one thing. v0.8.15 means fifteen. The patch count IS the quality metric.
### What v0.8.0 Requires
| Requirement | Status |
|-------------|--------|
| All 16 Known Issues resolved in code | **Done** (2026-03-25) |
| Section 17: c.Process() primitive | **Done** — Action sugar |
| Section 18: Action/Task system | **Done** — Action, Task, PerformAsync, type Task any removed |
| Section 19: c.API() streams | **Done** — Stream interface, protocol handlers, RemoteAction |
| Section 20: Registry[T] primitive | **Done** — all 5 registries migrated |
| Section 21: Entitlement primitive | **Done** — Entitled(), SetEntitlementChecker(), RecordUsage(), Action.Run() enforcement |
| AX-7 test coverage at 100% | **Done** — core/go 483 tests (100% naming) |
| Zero os/exec in core/go | **Done** — App.Find() uses os.Stat |
| type Task any removed | **Done** — PerformAsync takes named action + Options |
| Startable/Stoppable return Result | **Done** — breaking, clean |
| CommandLifecycle removed | **Done** → Command.Managed field |
| Consumer RFCs written | **Done** — go-process/docs/RFC.md, core/agent/docs/RFC.md |
### What Blocks v0.8.0 Tag
- go-process v0.7.0 alignment (consumer RFC written, ready to implement)
- core/agent v0.8.0 migration (consumer RFC written, Phase 1 ready)
### What Does NOT Block v0.8.0
- Ecosystem sweep (after consumers align)
- core/cli update (extension, not primitive)
1. **RFC spec** — design the version in prose
2. **Implement** — build to spec with AX-7 tests
3. **Refine** — review passes catch drift
4. **Tag** — when all sections pass
5. **Measure** — patches tell you what was missed
## 21. Entitlement — The Permission Primitive