chore: remove completed implementation plans — RFC.md is the single source

Plans 1-5 are implemented. Plan 6 (ecosystem sweep) is in consumer RFCs.
RFC.plan.md, RFC.plan.1.md, RFC.plan.2.md served their purpose as
session continuity docs — the work they described is done.

RFC.md (1935 lines) is now the single source of truth for core/go.

Removed:
- RFC.implementation.{1-6}.md
- RFC.plan.md, RFC.plan.1.md, RFC.plan.2.md

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-25 16:35:33 +00:00
parent fe46e33ddf
commit 390b392dec
9 changed files with 0 additions and 783 deletions

View file

@ -1,78 +0,0 @@
# Implementation Plan 1 — Critical Bug Fixes (Phase 1)
> Ship as v0.7.1. Zero consumer breakage. Fix the 3 critical bugs.
## P4-3: ACTION !OK Stops Broadcast Chain
**File:** `ipc.go`
**Change:** ACTION dispatch must call ALL handlers regardless of individual results.
```go
// Current (broken):
for _, h := range handlers {
if r := h(c, msg); !r.OK {
return r // STOPS — remaining handlers never called
}
}
// Fix:
for _, h := range handlers {
h(c, msg) // call all, ignore individual results for broadcast
}
```
**Test:** `TestIpc_Action_Ugly` — register 3 handlers, second returns !OK, verify third still fires.
## P7-2: No Cleanup on Startup Failure
**File:** `core.go``Run()`
**Change:** Call ServiceShutdown before exit on startup failure.
```go
// Current:
if !r.OK { os.Exit(1) }
// Fix:
if !r.OK {
c.ServiceShutdown(context.Background())
os.Exit(1)
}
```
## P7-3: ACTION Handlers No Panic Recovery
**File:** `ipc.go`
**Change:** Wrap each handler in defer/recover.
```go
for _, h := range handlers {
func() {
defer func() {
if r := recover(); r != nil {
Error("ACTION handler panicked", "panic", r)
}
}()
h(c, msg)
}()
}
```
**Test:** `TestIpc_Action_Ugly` — handler that panics, verify other handlers still execute.
## P7-4: Run() Needs defer ServiceShutdown
**File:** `core.go`
**Change:** Add defer as first line of Run.
```go
func (c *Core) Run() {
defer c.ServiceShutdown(context.Background())
// ... rest unchanged, but remove os.Exit calls
}
```
## Additional Phase 1 (safe)
- **I3:** Remove `Embed()` accessor (0 consumers)
- **I15:** Fix stale comment on `New()` — update to show `*Core` return
- **P9-1:** Remove `os/exec` import from `app.go` — move `App.Find()` to go-process

View file

@ -1,65 +0,0 @@
# Implementation Plan 2 — Registry[T] Primitive (Section 20)
> Foundation brick. Most other plans depend on this.
## The Type
**New file:** `registry.go`
```go
type Registry[T any] struct {
items map[string]T
order []string // insertion order (fixes P4-1)
mu sync.RWMutex
mode registryMode // open, sealed, locked
}
type registryMode int
const (
registryOpen registryMode = iota // anything goes
registrySealed // update existing, no new keys
registryLocked // fully frozen
)
```
## Methods
```go
func NewRegistry[T any]() *Registry[T]
func (r *Registry[T]) Set(name string, item T) Result
func (r *Registry[T]) Get(name string) Result
func (r *Registry[T]) Has(name string) bool
func (r *Registry[T]) Names() []string // insertion order
func (r *Registry[T]) List(pattern string) []T // glob match
func (r *Registry[T]) Each(fn func(string, T))
func (r *Registry[T]) Len() int
func (r *Registry[T]) Delete(name string) Result
func (r *Registry[T]) Disable(name string) // soft — exists but skipped
func (r *Registry[T]) Lock() // fully frozen
func (r *Registry[T]) Seal() // no new, updates OK
func (r *Registry[T]) Open() // default
```
## Migration
Replace internal registries one at a time:
1. `serviceRegistry``ServiceRegistry` embedding `Registry[*Service]`
2. `commandRegistry``CommandRegistry` embedding `Registry[*Command]`
3. `Drive.handles` → embed `Registry[*DriveHandle]`
4. `Data.mounts` → embed `Registry[*Embed]`
5. `Lock.locks``Registry[*sync.RWMutex]` (fixes P4-8 allocation)
Each migration is a separate commit. Tests before and after.
## Core Accessor
```go
func (c *Core) Registry(name string) *Registry[any]
```
Returns named registries for cross-cutting queries.
## Resolves
P4-1 (startup order), P4-8 (lock allocation), I6 (serviceRegistry unexported), I12 (Ipc data-only), I13 (Lock allocation), I14 (Startables return type).

View file

@ -1,98 +0,0 @@
# Implementation Plan 3 — Action/Task System (Section 18)
> Depends on: Plan 2 (Registry). The execution primitive.
## Phase A: Action Registry
**New file:** `action.go` (renamed from `task.go`)
```go
type ActionDef struct {
Name string
Handler ActionHandler
Description string
Schema Options // expected input keys
enabled bool // for Disable()
}
type ActionHandler func(context.Context, Options) Result
```
**Core accessor:**
```go
// Dual-purpose (like Service):
c.Action("process.run", handler) // register
c.Action("process.run").Run(ctx, opts) // invoke
c.Action("process.run").Exists() // check
c.Action("process.run").Def() // metadata
```
Internally uses `Registry[*ActionDef]`.
## Phase B: Move Registration to IPC
Move from `task.go`:
- `RegisterAction``ipc.go` (registers in `Registry[ActionHandler]`)
- `RegisterActions``ipc.go`
- `RegisterTask``ipc.go`
Keep in `action.go`:
- `Perform` → becomes `c.Action("name").Run()`
- `PerformAsync` → becomes `c.Action("name").RunAsync()`
- `Progress` → stays
## Phase C: Panic Recovery on All Actions
Every `Action.Run()` wraps in recover:
```go
func (a *ActionDef) Run(ctx context.Context, opts Options) (result Result) {
defer func() {
if r := recover(); r != nil {
result = Result{E("action.Run", Sprint("panic: ", r), nil), false}
}
}()
return a.Handler(ctx, opts)
}
```
## Phase D: Task Composition (v0.8.0 stretch)
```go
type TaskDef struct {
Name string
Steps []Step
}
type Step struct {
Action string
With Options
Async bool // run in background
Input string // "previous" = output of last step
}
```
`c.Task("name", def)` registers. `c.Task("name").Run(ctx)` executes steps in order.
## Resolves
I16 (task.go concerns), P6-1 (cascade → Task pipeline), P6-2 (O(N×M) → direct dispatch), P7-3 (panic recovery), P7-8 (circuit breaker via Disable), P10-2 (PERFORM not ACTION for request/response).
## Migration in core/agent
After Actions exist, refactor `handlers.go`:
```go
// Current: nested c.ACTION() cascade
// Target:
c.Task("agent.completion", TaskDef{
Steps: []Step{
{Action: "agentic.qa"},
{Action: "agentic.auto-pr"},
{Action: "agentic.verify"},
{Action: "agentic.ingest", Async: true},
{Action: "agentic.poke", Async: true},
},
})
```

View file

@ -1,100 +0,0 @@
# Implementation Plan 4 — c.Process() Primitive (Section 17)
> Depends on: Plan 2 (Registry), Plan 3 (Actions).
> go-process v0.7.0 update required.
## Phase A: Update go-process to v0.7.0 Core API
**Repo:** core/go-process
1. Change `NewService` factory to return `core.Result` (not `(any, error)`)
2. Add `Register` function matching `WithService` signature
3. Remove `ProcessRegister` bridge from core/agent
4. Register process Actions during OnStartup:
```go
func (s *Service) OnStartup(ctx context.Context) core.Result {
c := s.Core()
c.Action("process.run", s.handleRun)
c.Action("process.start", s.handleStart)
c.Action("process.kill", s.handleKill)
return core.Result{OK: true}
}
```
## Phase B: Add Process Primitive to core/go
**New file in core/go:** `process.go`
```go
type Process struct {
core *Core
}
func (c *Core) Process() *Process { return c.process }
func (p *Process) Run(ctx context.Context, command string, args ...string) Result {
return p.core.Action("process.run").Run(ctx, NewOptions(
Option{Key: "command", Value: command},
Option{Key: "args", Value: args},
))
}
func (p *Process) RunIn(ctx context.Context, dir, command string, args ...string) Result {
return p.core.Action("process.run").Run(ctx, NewOptions(
Option{Key: "command", Value: command},
Option{Key: "args", Value: args},
Option{Key: "dir", Value: dir},
))
}
```
No new dependencies in core/go — Process is just Action sugar.
## Phase C: Migrate core/agent proc.go
Replace standalone helpers with Core methods:
```go
// Current: proc.go standalone with ensureProcess() hack
out, err := runCmd(ctx, dir, "git", "log")
// Target: method on PrepSubsystem using Core
out := s.core.Process().RunIn(ctx, dir, "git", "log")
```
Delete `proc.go`. Delete `ensureProcess()`. Delete `ProcessRegister`.
## Phase D: Replace syscall.Kill calls
5 call sites in core/agent use `syscall.Kill(pid, 0)` and `syscall.Kill(pid, SIGTERM)`.
Replace with:
```go
processIsRunning(st.ProcessID, st.PID) // already in proc.go
processKill(st.ProcessID, st.PID) // already in proc.go
```
These use `process.Get(id).IsRunning()` when ProcessID is available.
## Phase E: Atomic File Writes (P4-10)
Add to core/go `fs.go`:
```go
func (m *Fs) WriteAtomic(p, content string) Result {
tmp := p + ".tmp." + strconv.FormatInt(time.Now().UnixNano(), 36)
if r := m.Write(tmp, content); !r.OK { return r }
if err := os.Rename(tmp, m.path(p)); err != nil {
m.Delete(tmp)
return Result{err, false}
}
return Result{OK: true}
}
```
Migrate `writeStatus` in core/agent to use `WriteAtomic`. Fixes P4-9 (51 race sites).
## Resolves
I7 (no c.Process), P9-1 (os/exec in core), P4-9 (status.json race), P4-10 (Fs.Write not atomic), P11-2 (unsafe.Pointer Fs bypass — add Fs.NewUnrestricted instead).

View file

@ -1,121 +0,0 @@
# Implementation Plan 5 — Missing Primitives + AX-7 (Phase 1-2)
> Independent of Plans 2-4. Can ship alongside or before.
## core.ID() — Unique Identifier
**File:** `utils.go` or new `id.go`
```go
var idCounter atomic.Uint64
func ID() string {
return Sprintf("id-%d-%s", idCounter.Add(1), shortRand())
}
func shortRand() string {
b := make([]byte, 3)
crand.Read(b)
return hex.EncodeToString(b)
}
```
Replaces 3 different patterns: crypto/rand hex, atomic counter, fmt.Sprintf.
## core.ValidateName() / core.ValidatePath()
**File:** `utils.go` or new `validate.go`
```go
func ValidateName(name string) Result {
if name == "" || name == "." || name == ".." {
return Result{E("validate", "invalid name: "+name, nil), false}
}
if Contains(name, "/") || Contains(name, "\\") {
return Result{E("validate", "name contains path separator: "+name, nil), false}
}
return Result{name, true}
}
func SanitisePath(path string) string {
safe := PathBase(path)
if safe == "." || safe == ".." || safe == "" {
return "invalid"
}
return safe
}
```
Replaces copy-pasted validation in prep.go, plan.go, command.go.
## Fs.WriteAtomic()
See Plan 4 Phase E. Fixes P4-9 and P4-10.
## Fs.NewUnrestricted()
**File:** `fs.go`
```go
func (m *Fs) NewUnrestricted() *Fs {
return m.New("/")
}
```
Gives consumers a legitimate door instead of unsafe.Pointer crowbar.
Fixes P11-2. Add go vet / linter rule to flag unsafe.Pointer on Core types.
## AX-7 for core/go
Currently 14% AX-7 (83.6% statement coverage, wrong naming).
Steps:
1. Run the rename script from core/agent (same Python script)
2. Gap analysis: find functions missing Good/Bad/Ugly
3. Fill gaps — 212 functions × 3 categories = 636 target
4. Currently 91/636 filled → need 545 more
Prioritise by section:
- Section 3 (services): ServiceFor, RegisterService, Service
- Section 4 (IPC): Action, Query, RegisterAction
- Section 8 (Fs): Read, Write, WriteAtomic, Delete
- Section 5 (Config): Get, Set, Enable, ConfigGet
## RunE() — Backwards-Compatible Run Fix
**File:** `core.go`
```go
func (c *Core) RunE() error {
defer c.ServiceShutdown(context.Background())
r := c.ServiceStartup(c.context, nil)
if !r.OK {
if err, ok := r.Value.(error); ok {
return err
}
return E("core.Run", "startup failed", nil)
}
if cli := c.Cli(); cli != nil {
r = cli.Run()
}
if !r.OK {
if err, ok := r.Value.(error); ok {
return err
}
}
return nil
}
// Run keeps backwards compatibility
func (c *Core) Run() {
if err := c.RunE(); err != nil {
Error(err.Error())
os.Exit(1)
}
}
```
Fixes P7-5 (os.Exit bypasses defer) without breaking 15 main.go files.

View file

@ -1,83 +0,0 @@
# Implementation Plan 6 — Ecosystem Sweep (Phase 3)
> Depends on: Plans 1-5 complete. 44 repos need updating.
> Use Codex dispatch with RFC as the spec.
## Breaking Changes
### StartableV2 (if P3-1 adopted)
```go
type StartableV2 interface {
OnStartup(ctx context.Context) Result
}
```
Core checks V2 first, falls back to V1. No breakage. Deprecation notice on V1.
**Codex template:** "If this repo implements OnStartup returning error, add a V2 variant returning core.Result alongside it."
### RunE() exists alongside Run()
No breakage — Run() still works. New code uses RunE().
### Command.Managed replaces CommandLifecycle
```go
// Old:
Command{Lifecycle: myLifecycle}
// New:
Command{Managed: "process.daemon"}
```
**Codex template:** "If this repo uses Command.Lifecycle, replace with Managed field."
## Per-Repo Sweep Checklist
For each of 44 repos:
1. [ ] Update `go.mod` to core v0.8.0
2. [ ] Replace `OnStartup() error` with `OnStartup() Result` (if V2 adopted)
3. [ ] Replace `os/exec` with `c.Process()` calls
4. [ ] Replace manual `unsafe.Pointer` Fs hacks with `Fs.NewUnrestricted()`
5. [ ] Run AX-7 gap analysis, fill missing Good/Bad/Ugly
6. [ ] Rename tests to `TestFile_Function_{Good,Bad,Ugly}`
7. [ ] Add `llm.txt` and `AGENTS.md`
8. [ ] Verify `go test ./...` passes
9. [ ] Create PR to dev
## Dispatch Strategy
```
Batch 1 (core packages — we control):
core/go, core/agent, core/mcp, go-process, go-io, go-log
Batch 2 (utility packages):
go-config, go-git, go-scm, go-cache, go-store, go-session
Batch 3 (domain packages):
go-forge, go-api, go-build, go-devops, go-container
Batch 4 (application packages):
gui, cli, ts, php, ide, lint
Batch 5 (research/experimental):
go-ai, go-ml, go-mlx, go-inference, go-rag, go-rocm
```
Each batch is one Codex sweep. Verify batch N before starting N+1.
## Success Criteria for v0.8.0
- [ ] All 3 critical bugs fixed (Plan 1)
- [ ] Registry[T] implemented and migrated (Plan 2)
- [ ] Action system working (Plan 3 Phase A-C)
- [ ] c.Process() primitive working (Plan 4 Phase A-C)
- [ ] Missing primitives added (Plan 5)
- [ ] core/go AX-7 at 100%
- [ ] core/agent AX-7 at 100%
- [ ] Zero os/exec in core/go
- [ ] Zero unsafe.Pointer on Core types in ecosystem
- [ ] All Phase 1-2 changes shipped
- [ ] Phase 3 sweep at least started (batch 1-2)

View file

@ -1,85 +0,0 @@
# RFC Plan 1 — First Session Priorities (COMPLETED 2026-03-25)
> All items shipped. See RFC.plan.md "What Was Shipped" section.
## Priority 1: Fix the 3 Critical Bugs (Plan 1)
These are one-line to five-line changes. Ship as v0.7.1.
### Bug 1: ACTION stops on !OK (ipc.go line ~33)
```go
// CURRENT (broken — handler 3 failing silences handlers 4 and 5):
for _, h := range handlers {
if r := h(c, msg); !r.OK { return r }
}
// FIX:
for _, h := range handlers {
func() {
defer func() { if r := recover(); r != nil { Error("handler panic", "err", r) } }()
h(c, msg)
}()
}
```
This also fixes P7-3 (no panic recovery) in the same change.
### Bug 2: Run() leaks on startup failure (core.go Run method)
Add one line:
```go
func (c *Core) Run() {
defer c.ServiceShutdown(context.Background()) // ADD THIS
// ... rest unchanged
}
```
### Bug 3: Remove stale Embed() and fix comment
Delete `func (c *Core) Embed() Result` from core.go.
Fix the `New()` comment to show `*Core` return.
### Test all 3 with AX-7 naming:
```
TestIpc_Action_Ugly_HandlerFailsChainContinues
TestIpc_Action_Ugly_HandlerPanicsChainContinues
TestCore_Run_Ugly_StartupFailureCallsShutdown
```
## Priority 2: AX-7 Rename for core/go
Run the same Python rename script used on core/agent:
```python
# Same script from core/agent session — applies to any Go package
# Changes TestFoo_Good to TestFile_Foo_Good
```
This is mechanical. No logic changes. Just naming.
Then run gap analysis:
```bash
python3 -c "... same gap analysis script ..."
```
## Priority 3: Start Registry[T] (Plan 2)
Create `registry.go` with the type. Write tests FIRST (AX-7 complete from day one):
```
TestRegistry_Set_Good
TestRegistry_Set_Bad
TestRegistry_Set_Ugly
TestRegistry_Get_Good
...
```
Then migrate `serviceRegistry` first (most tested, most used).
## What Was Skipped (shipped in same session instead)
All items originally marked "skip" were shipped because Registry and Actions were built in the same session:
- Plan 3 (Actions) — DONE: ActionDef, TaskDef, c.Action(), c.Task()
- Plan 4 (Process) — DONE for core/go: c.Process() sugar over Actions
- Breaking changes — DONE: Startable returns Result, CommandLifecycle removed

View file

@ -1,43 +0,0 @@
# RFC Plan 2 — Registry + Actions Sessions (COMPLETED 2026-03-25)
> All core/go items shipped. core/agent migration and go-process v0.7.0 are separate repo scope.
## Session Goal: Registry[T] + First Migration
1. Build `registry.go` with full AX-7 tests
2. Migrate `serviceRegistry``ServiceRegistry` embedding `Registry[*Service]`
3. Verify all existing tests still pass
4. Commit + push
## Session Goal: Action System
1. Rename `task.go``action.go`
2. Move `RegisterAction`/`RegisterActions`/`RegisterTask` to `ipc.go`
3. Build `ActionDef` type with `Run()`, `Exists()`, `Def()`
4. Wire `c.Action("name")` dual-purpose accessor
5. Full AX-7 tests
6. Commit + push
## Session Goal: Migrate core/agent Handlers
1. Register named Actions in `agentic.Register()`
2. Replace nested `c.ACTION()` cascade with Task pipeline
3. Test that queue drains properly after agent completion
4. This is the P6-1 fix — the queue starvation bug
## Session Goal: c.Process() + go-process v0.7.0
1. Update go-process factory to return `core.Result`
2. Add `process.Register` direct factory
3. Remove `agentic.ProcessRegister` bridge
4. Add `Process` primitive to core/go (sugar over Actions)
5. Migrate core/agent `proc.go``s.core.Process()` calls
6. Delete `proc.go` and `ensureProcess()`
## Between Sessions
Each session should produce:
- Working code (all tests pass)
- A commit with conventional message
- Updated coverage numbers
- Any new findings added to RFC.md passes

View file

@ -1,110 +0,0 @@
# RFC Plan — How to Work With This Spec
> For future Claude sessions. Read this FIRST before touching code.
## What Exists
- `docs/RFC.md` — 3,845-line API spec with 108 findings across 13 passes
- `docs/RFC.implementation.{1-6}.md` — ordered implementation plans
- `llm.txt` — agent entry point
- `CLAUDE.md` — session-specific instructions
## The 108 Findings Reduce to 5 Root Causes
1. **Type erasure** (16 findings) — `Result{Value: any}` loses compile-time safety. Mitigate with typed methods + AX-7 tests. Not fixable without abandoning Result.
2. **No internal boundaries** (14 findings) — `*Core` grants God Mode. Solved by Section 21 (Entitlement primitive). v0.8.0 scope — designed, implementation pending.
3. **Synchronous everything** (12 findings) — IPC dispatch blocks. ACTION cascade in core/agent blocks queue for minutes. Fixed by Action/Task system (Plan 3).
4. **No recovery path** (10 findings) — `os.Exit` bypasses defer. No cleanup on failure. Fixed by Plan 1 (defer + RunE + panic recovery).
5. **Missing primitives** (8 findings) — No ID, validation, health, atomic writes. Fixed by Plan 5.
## Implementation Order
```
Plan 1 → v0.7.1 (ship immediately, zero breakage)
Plan 2 → Registry[T] (foundation — Plans 3-4 depend on this)
Plan 3 → Action/Task (execution primitive — Plan 4 depends on this)
Plan 4 → c.Process() (needs go-process v0.7.0 update first)
Plan 5 → Missing primitives + AX-7 (independent, do alongside 2-4)
Plan 6 → Ecosystem sweep (after 1-5, dispatched via Codex)
```
## 3 Critical Bugs — Fix First
1. **P4-3:** `ipc.go` — ACTION handler returning `!OK` stops entire broadcast chain. Other handlers never fire. Fix: call all handlers, don't stop on failure.
2. **P6-1:** core/agent `handlers.go` — Nested `c.ACTION()` calls create synchronous cascade 4 levels deep. QA → PR → Verify → Merge blocks Poke handler for minutes. Queue doesn't drain. Fix: replace with Task pipeline (needs Plan 3).
3. **P7-2:** `core.go``Run()` calls `os.Exit(1)` on startup failure without calling `ServiceShutdown()`. Running services leak. Fix: add `defer c.ServiceShutdown()` + replace `os.Exit` with error return.
## Key Design Decisions Already Made
- **CamelCase = primitive** (brick), **UPPERCASE = convenience** (sugar)
- **Core is Lego bricks** — export the bricks, hide the safety mechanisms
- **Fs.root is the ONE exception** — security boundaries stay unexported
- **Registration IS permission** — no handler = no capability
- **`error` at Go interface boundary, `Result` at Core contract boundary**
- **Dual-purpose methods** (Service, Command, Action) — keep as sugar, Registry has explicit Get/Set
- **Array[T] and ConfigVar[T] are guardrail primitives** — model-proof, not speculative
- **ServiceRuntime[T] and manual `.core = c` are both valid** — document both
- **Startable returns Result** — clean break, no V2 compat shim (pre-v1, breaking is expected)
- **`RunE()` alongside `Run()`** — no breakage
- **CommandLifecycle removed** — replaced with `Command.Managed` string field
## Existing RFCs That Solve Open Problems
| Problem | RFC | Core Provides | Consumer Implements |
|---------|-----|---------------|-------------------|
| Permissions | RFC-004 Entitlements | `c.Entitlement()` interface | go-entitlements package |
| Config context | RFC-003 Config Channels | `c.Config()` with channel | config channel service |
| Secrets | RFC-012 SMSG | `c.Secret()` interface | go-smsg / env fallback |
| Validation | RFC-009 Sigil | Transform chain interface | validator implementations |
| Containers | RFC-014 TIM | `c.Fs()` sandbox | TIM = OS isolation |
| In-memory fs | RFC-013 DataNode | `c.Data()` mounts fs.FS | DataNode / Borg |
| Lazy startup | RFC-002 Event Modules | Event declaration | Lazy instantiation |
Core stays stdlib-only. Consumers bring implementations via WithService.
## What NOT to Do
- Don't add dependencies to core/go (it's stdlib + go-io + go-log only)
- Don't use `os/exec` — go-process is the only allowed user (P9-1: core/go itself violates this in app.go — fix it)
- Don't use `unsafe.Pointer` on Core types — add legitimate APIs instead
- Don't call `os.Exit` inside Core — return errors, let main() exit
- Don't create global mutable state — use Core's Registry
- Don't auto-discover via reflect — use explicit registration (HandleIPCEvents is the last magic method)
## AX-7 Status
- core/agent: 92% (840 tests, 79.9% coverage)
- core/go: **100%** (457 tests, 84.4% coverage) — renamed 2026-03-25
- All 457 tests have `TestFile_Function_{Good,Bad,Ugly}` naming
## What Was Shipped (2026-03-25 session)
Plans 1-5 complete for core/go scope. 457 tests, 84.4% coverage, 100% AX-7 naming.
- P4-3 + P7-3: ACTION broadcast — calls all handlers, panic recovery per handler
- P7-2 + P7-4: `RunE()` with `defer ServiceShutdown`, `Run()` delegates
- P3-1: Startable/Stoppable return `Result` (breaking, clean — no V2)
- P9-1: Zero `os/exec` in core/go — `App.Find()` rewritten with `os.Stat` + PATH
- P11-2: `Fs.NewUnrestricted()` — legitimate door replaces unsafe.Pointer
- P4-10: `Fs.WriteAtomic()` — write-to-temp-then-rename
- I3: `Embed()` removed, I15: `New()` comment fixed
- I9: `CommandLifecycle` interface removed → `Command.Managed` string field
- Section 17: `c.Process()` primitive (Action sugar, no deps)
- Section 18: `c.Action("name")` + `ActionDef` + `c.Task("name", TaskDef{Steps})` composition
- Section 20: `Registry[T]` + all 5 migrations (services, commands, drive, data, lock)
- Section 20.4: `c.RegistryOf("name")` cross-cutting accessor
- Plan 5: `core.ID()`, `ValidateName()`, `SanitisePath()`
## Session Context That Won't Be In Memory
- The ACTION cascade (P6-1) — core/go now has TaskDef for the fix, core/agent needs to wire it
- status.json has 51 unprotected read-modify-write sites (P4-9) — `WriteAtomic` exists, core/agent needs to use it
- `core.Env("DIR_HOME")` is cached at init — `t.Setenv` doesn't override it (P2-5) — use `CORE_WORKSPACE` in tests
- go-process `NewService` returns `(any, error)` not `core.Result` — needs v0.7.0 update (go-process repo)
- Multiple Core instances share global state (assetGroups, systemInfo, defaultLog)