Commit graph

188 commits

Author SHA1 Message Date
Snider
c91f96d89d fix(rfc): pass 8 — cross-ref table: open→resolved, remove phantom c.Secret()
- "Open Problems" → "Ecosystem RFCs" (they're resolved)
- c.Secret(name) removed (not implemented — future primitive)
- P11-2 resolution: Fs.NewUnrestricted() not TIM
- Simplified table columns

3 items found — diminishing returns confirmed.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 17:02:31 +00:00
Snider
340b8173a4 fix(rfc): pass 7 — 4 items: insertion order, RunE, Plan 6 ref, Design spec tag
Findings are converging — 4 items this pass vs 7 last pass.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 17:01:31 +00:00
Snider
7b68ead3b0 fix(rfc): pass 6 — root cause table done, method names, test count
- Priority table: Phase references → Done status
- Root Cause 5: "designed" → "Done"
- Cross-ref table: c.Entitlement→c.Entitled, bool→Entitlement
- Removed c.Secret() (not implemented) from examples
- Cadence: future tense → present tense (process description)
- Requirements: ActionDef/TaskDef rename cruft removed
- Test count: 456→483
- Simplified entitlement example block

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:59:36 +00:00
Snider
da2e5477ea fix(rfc): pass 5 — PERFORM→Actions, Entitlement→Entitled, RunE, Task rename
- AX principle 5: PERFORM removed, now ACTION/QUERY + named Actions
- Findings table: TaskDef → Task
- Root Cause 2: removed stale v0.8.0 framing, Entitlement→Entitled method name
- Root Cause 3: TaskDef→Task, linked to core/agent RFC not deleted plan file
- Root Cause 4: Run()→RunE() in code example
- Root Cause 5: Updated to show resolved items vs open items
- Fixed triple blank line, cleaned whitespace

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:57:31 +00:00
Snider
d33765c868 fix(rfc): pass 4 — RegistryOf not Registry, implementation pending→done
- c.Registry("x") → c.RegistryOf("x") (3 occurrences)
- serviceRegistry → ServiceRegistry in export rules
- Removed speculative core/go-cli from layer list
- Entitlement "implementation pending" → "implemented" (3 occurrences)
- Removed Section 21.13 implementation plan (done)
- Cleaned changelog — one line per era, not per discovery step
- Fixed double blank line

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:55:09 +00:00
Snider
377afa0cbe fix(rfc): pass 3 — rewrite Sections 18, 19, 20 to match implementation
Section 18: Removed PERFORM references, ActionDef→Action, TaskDef→Task,
  OnStartup returns Result, removed aspirational patterns (Parallel,
  Conditional, Scheduled), kept what's implemented.

Section 19: Removed old struct definition, Stream returns Result not
  (Stream, error), RemoteAction uses c.RemoteAction() not c.Action(),
  removed stale subsystem map, added Web3 snider.lthn example.

Section 20: Removed migration history (20.1 The Problem, 20.6-20.8),
  kept the API contract. Added 20.6 "What Embeds Registry" reference.

4193 → 1519 lines (64% reduction total).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:51:51 +00:00
Snider
7069def5b8 fix(rfc): rewrite Section 17 — match implementation, remove consumer detail
Section 17 was 240 lines of design spec with old signatures.
Now 30 lines matching the actual Process primitive.
Consumer detail (ProcessHandle, IPC messages) lives in go-process/docs/RFC.md.

Section 18 stale items identified for next pass.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:48:01 +00:00
Snider
b0e54a850a fix(rfc): review pass — update stale specs found at 60%+ context
- Section 1.2: Added RunE() to lifecycle, clarified defer ServiceShutdown
- Section 4.1: Handler results are ignored, panic recovery per handler
- Section 6: Documented Data embeds Registry[*Embed]
- Section 7: Documented Drive embeds Registry[*DriveHandle]
- Section 14: Added core.ID(), ValidateName(), SanitisePath()

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:44:39 +00:00
Snider
a26d9437bb fix(rfc): update stale specs to match v0.8.0 implementation
- Version header: v0.7.0+ → v0.8.0
- Section 2.4: type Task any removed, PERFORM replaced by PerformAsync
- Section 3.3+3.5: Startable/Stoppable return Result not error
- Section 4.3: PERFORM → PerformAsync with named action + Options
- Section 1.3: Added Process, API, Action, Task, Entitled, RegistryOf
- Section 8: Added WriteAtomic, NewUnrestricted, Root
- Section 9: Added Command.Managed field
- Description updated to include "permission"

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:40:47 +00:00
Snider
390b392dec 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>
2026-03-25 16:35:33 +00:00
Snider
fe46e33ddf refactor(rfc): trim RFC.md from 4193 to 1935 lines (54% reduction)
All 16 Known Issues replaced with resolved summary table.
All 12 passes (108 findings) replaced with findings summary table.
Full discovery detail preserved in git history.

What remains: 21 feature sections (the API contract), Design Philosophy,
AX Principles, root cause synthesis, consumer RFCs, versioning.

No "Planned" tags. No unresolved findings. No v0.9.0 deferrals.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:32:31 +00:00
Snider
77563beecf docs(rfc): all 21 sections implemented — v0.8.0 requirements met
Section 19 (API streams) and Section 21 (Entitlements) now implemented.
483 tests, 84.7% coverage, 100% AX-7 naming.

Remaining v0.8.0 blockers: consumer alignment (go-process, core/agent).
Consumer RFCs written and ready for implementation.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:22:33 +00:00
Snider
14cd9c6adb fix(rfc): remove all v0.9.0 deferrals — everything is v0.8.0
v0.8.0 IS the production release. There is no v0.9.0 to defer to.
All 8 references to v0.9.0 updated:
- P11-1: Entitlements are Section 21, v0.8.0 scope
- P13-5: Async startup is future enhancement, not version-gated
- P13-6: Registry Seal/Lock enables hot-reload patterns
- Root Cause 2+5: Section 21 designed, implementation pending
- Versioning: v0.8.0 = production, v0.8.* patches = quality metric
- Section 21 header: v0.8.0 boundary model
- Config/Data/Fs gating: same pattern, more integration points

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:10:42 +00:00
Snider
1d174a93ce docs(rfc): update RFC.md — consumer RFCs, versioning, v0.8.0 status
- Added Consumer RFCs section pointing to go-process and core/agent RFCs
- Updated versioning to reflect v0.8.0 as current (Plans 1-5 done)
- Updated v0.8.0 requirements checklist — most items done
- Cross-referenced P6-1 fix to core/agent migration plan
- Updated Root Cause 2 to reference Section 21 (Entitlement)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 16:01:59 +00:00
Snider
028ec84c5e fix: remove type Task any — untyped IPC replaced by named Actions
The old IPC Task system passed `any` through TaskHandler and
PerformAsync. Now that named Actions exist with typed signatures
(ActionHandler func(context.Context, Options) Result), the untyped
layer is dead weight.

Changes:
- type Task any removed (was in contract.go)
- type Task struct is now the composed sequence (action.go)
- PerformAsync takes (action string, opts Options) not (t Task)
- TaskHandler type removed — use c.Action("name", handler)
- RegisterTask removed — use c.Action("name", handler)
- PERFORM sugar removed — use c.Action("name").Run()
- ActionTaskStarted/Progress/Completed carry typed fields
  (Action string, Options, Result) not any

ActionDef → Action rename also in this commit (same principle:
DTOs don't have Run() methods).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 15:57:36 +00:00
Snider
c5c16a7a21 feat(rfc): Section 21 — Entitlement permission primitive design
Bridges RFC-004 (SaaS feature gating), RFC-005 (Commerce Matrix
hierarchy), and Core Actions into one permission primitive.

Key design: Entitlement struct carries Allowed/Unlimited/Limit/Used/
Remaining/Reason — maps 1:1 to both PHP implementations.
EntitlementChecker is a function registered by consumer packages.
Default is permissive (trusted conclave). Enforcement in Action.Run().

Implementation plan: ~100 lines, zero deps, 11 steps.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 15:23:00 +00:00
Snider
2dff772a40 feat: implement RFC plans 1-5 — Registry[T], Action/Task, Process, primitives
Plans 1-5 complete for core/go scope. 456 tests, 84.4% coverage, 100% AX-7 naming.

Critical bugs (Plan 1):
- P4-3+P7-3: ACTION broadcast calls all handlers with panic recovery
- P7-2+P7-4: RunE() with defer ServiceShutdown, Run() delegates
- P3-1: Startable/Stoppable return Result (breaking, clean)
- P9-1: Zero os/exec — App.Find() rewritten with os.Stat+PATH
- I3: Embed() removed, I15: New() comment fixed
- I9: CommandLifecycle removed → Command.Managed field

Registry[T] (Plan 2):
- Universal thread-safe named collection with 3 lock modes
- All 5 registries migrated: services, commands, drive, data, lock
- Insertion order preserved (fixes P4-1)
- c.RegistryOf("name") cross-cutting accessor

Action/Task system (Plan 3):
- Action type with Run()/Exists(), ActionHandler signature
- c.Action("name") dual-purpose accessor (register/invoke)
- TaskDef with Steps — sequential chain, async dispatch, previous-input piping
- Panic recovery on all Action execution
- broadcast() internal, ACTION() sugar

Process primitive (Plan 4):
- c.Process() returns Action sugar — Run/RunIn/RunWithEnv/Start/Kill/Exists
- No deps added — delegates to c.Action("process.*")
- Permission-by-registration: no handler = no capability

Missing primitives (Plan 5):
- core.ID() — atomic counter + crypto/rand suffix
- ValidateName() / SanitisePath() — reusable validation
- Fs.WriteAtomic() — write-to-temp-then-rename
- Fs.NewUnrestricted() / Fs.Root() — legitimate sandbox bypass
- AX-7: 456/456 tests renamed to TestFile_Function_{Good,Bad,Ugly}

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 15:18:25 +00:00
Snider
0704a7a65b feat: session continuity plans — RFC.plan.md + plan.1 + plan.2
RFC.plan.md: master context document for future sessions
  - 5 root causes, 3 critical bugs, key decisions, what NOT to do
  - Session context that won't survive compact
  - Cross-references to existing RFCs that solve problems

RFC.plan.1.md: first session priorities
  - Fix 3 critical bugs (one-line changes)
  - AX-7 rename for core/go
  - Start Registry[T]

RFC.plan.2.md: subsequent session goals
  - Registry + migration
  - Action system
  - core/agent cascade fix
  - c.Process() + go-process v0.7.0

Future sessions: read RFC.plan.md first, then the numbered plan
for that session's scope.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:35:14 +00:00
Snider
9cd83daaae feat: 6 implementation plans for v0.8.0
Plan 1: Critical bug fixes (v0.7.1, zero breakage)
  - ACTION chain, panic recovery, defer shutdown, stale code removal

Plan 2: Registry[T] primitive (Section 20)
  - Foundation brick, migration of 5 internal registries

Plan 3: Action/Task system (Section 18)
  - Named callables, task composition, cascade fix

Plan 4: c.Process() primitive (Section 17)
  - go-process v0.7.0, proc.go migration, atomic writes

Plan 5: Missing primitives + AX-7
  - core.ID(), ValidateName, WriteAtomic, RunE(), test coverage

Plan 6: Ecosystem sweep (Phase 3)
  - 44 repos in 5 batches, Codex dispatch with RFC as spec

Each plan lists: files to change, code examples, what it resolves,
dependencies on other plans, and migration strategy.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:31:11 +00:00
Snider
f7e91f0970 feat(rfc): cross-reference existing RFCs to open findings
7 existing RFCs solve open problems — Core provides the interface
(stdlib only), consumer packages bring the implementation:

- RFC-002 → lazy startup (P13-5)
- RFC-004 → entitlements/permissions (P11-1)
- RFC-012 → secret storage via SMSG (P11-3)
- RFC-009 → validation via Sigil transforms (P9-6)
- RFC-014 → OS-level isolation via TIM containers (P11-2)
- RFC-013 → in-memory fs via DataNode (P13-2)
- RFC-003 → config channels for surface context (P2-8)

Pattern: core/go defines interface + default. Consumer registers
implementation. c.Secret() defaults to os.Getenv. go-smsg registers
SMSG decryptor. No deps injected into core/go.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:26:32 +00:00
Snider
c6403853f1 feat(rfc): Root Cause 2 resolved — Entitlements not CoreView
The boundary model already exists in CorePHP:
- RFC-004 (Entitlements): "can this workspace do this action?"
- RFC-003 (Config Channels): "what settings apply in this context?"

Registration = capability (action exists)
Entitlement = permission (action is allowed)

Port RFC-004 to CoreGO for v0.9.0 instead of inventing CoreView.
The concept is designed, implemented, and production-tested in PHP.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:23:19 +00:00
Snider
93c21cfd53 feat(rfc): Synthesis — 108 findings reduce to 5 root causes
With full session context (tests + refactoring + 13 passes + revisit),
the 108 findings cluster into 5 root causes:

1. Type erasure via Result{any} (16 findings)
   → mitigation: typed methods + AX-7 tests, not fixable without abandoning Result

2. No internal boundaries (14 findings)
   → by design for v0.8.0 (trusted conclave), CoreView for v0.9.0

3. Synchronous everything (12 findings)
   → Action/Task system is the fix, PERFORM replaces ACTION for request/response

4. No recovery path (10 findings)
   → one fix: defer ServiceShutdown + return error from Run() + panic recovery

5. Missing primitives (8 findings)
   → ID, Validate, Health needed. JSON/Time are judgment calls.

60 findings clustered, 48 remaining (specific/local).
Priority: recovery > sync > primitives > types > boundaries.

This is the definitive analysis. 3,800+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:21:11 +00:00
Snider
21c1a3e92b feat(rfc): Pass 4 Revisited — 4 deeper concurrency findings
Re-examined concurrency with full context from 13 passes.
Found races that P4 couldn't see:

P4-9:  status.json 51 read-modify-write sites with NO locking.
       spawnAgent goroutine vs status MCP tool vs drainOne vs shutdown
       — classic TOCTOU, status corruption in production.

P4-10: Fs.Write uses os.WriteFile (truncate+write, not atomic).
       Concurrent reader sees empty file during write window.
       Root cause of P4-9. Need WriteAtomic (temp+rename).

P4-11: Config map values shared by reference after Set.
       Goroutine mutates map retrieved from Config — unprotected.

P4-12: Global logger race — Default() may return nil before Core sets it.

P4-9 is likely causing real status corruption in production.
The 51 unprotected read-modify-write sites on status.json
explain workspace status inconsistencies.

108 findings total, 3,700+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:16:05 +00:00
Snider
ef548d07bc feat(rfc): Pass Thirteen — hidden assumptions, final review
P13-1: Single Core per process assumed — 5 globals break with multiple
P13-2: All services are Go — no plugin/remote service boundary
P13-3: Go only — but CorePHP and CoreTS exist (need concept mapping)
P13-4: Unix only — syscall.Kill, PID files, no Windows support
P13-5: Synchronous startup — 30s DB connect blocks everything
P13-6: Static conclave — no hot-loading, no runtime service addition
P13-7: IPC is ephemeral — no persistence, replay, or dead letter
P13-8: Single-perspective review — RFC needs adversarial input

Meta-finding: the RFC is the best single-session analysis possible.
It's not complete. Pass Fourteen starts next session.

FINAL TALLY:
- 13 passes
- 104 findings (3 critical, 12 high, ~50 medium, ~40 low)
- 20 spec sections + 4 planned primitives
- 3-phase migration plan for 44 repos
- 3,600+ lines

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:10:34 +00:00
Snider
1ef8846f29 feat(rfc): Pass Twelve — migration risk across 44 repos
44 repos import core/go. Breaking changes categorised into 3 phases:

Phase 1 (zero breakage, ship now):
- New accessors (Process, Action, API, Registry)
- Critical bug fixes (ACTION chain, panic recovery, cleanup)
- Remove dead code (Embed)

Phase 2 (internal refactor):
- task.go → action.go, move RegisterAction
- Remove os/exec from app.go
- Add Fs.NewUnrestricted to replace unsafe.Pointer hacks

Phase 3 (ecosystem sweep, 44 repos):
- Startable returns Result (26 files)
- Run() → RunE() (15 files)
- CommandLifecycle → Managed

Key insight: 3 critical bugs are Phase 1 — can ship as v0.7.1 tomorrow.
Biggest risk (Startable change) can use V2 interface for backwards compat.

Twelve passes, 96 findings, 3,500+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:08:19 +00:00
Snider
caa1dea83d feat(rfc): Pass Eleven — security model, God Mode, sandbox bypass
CRITICAL: P11-2 — The Fs sandbox (P2-2: "correctly unexported") is
bypassed by core/agent using unsafe.Pointer to overwrite Fs.root.
The security boundary exists in theory but is broken in practice.

P11-1: Every service has God Mode — full access to everything
P11-2: Fs.root bypassed via unsafe.Pointer (paths.go, detect.go)
P11-3: core.Env() exposes all secrets (API keys, tokens)
P11-4: ACTION event spoofing — fake AgentCompleted triggers pipeline
P11-5: RegisterAction installs spy handler (sees all IPC)
P11-6: No audit trail — no logging of security-relevant ops
P11-7: ServiceLock has no authentication (anyone can lock)
P11-8: No revocation — services join but can never be ejected

The conclave trust model: all first-party, no isolation.
Acceptable for v0.8.0 (trusted code). Needs capability model
for v0.9.0+ (plugins, third-party services).

Eleven passes, 88 findings, 3,400+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:05:47 +00:00
Snider
20f3ee30b8 feat(rfc): Pass Ten — the spec auditing itself, 80 findings total
P10-1: S17 and S18 contradict on Process return type
P10-2: S17 uses ACTION for request/response — should be PERFORM
P10-3: Subsystem count wrong (22 methods, not 14 subsystems)
P10-4: Four API patterns on one struct — undocumented categories
P10-5: Registry resolves old issues — needs cross-reference table
P10-6: Design Philosophy before reasoning — correct for RFC format
P10-7: v0.8.0 checklist missing 56 findings — added severity classification
       (3 critical, 12 high, 25 medium, 16 low)
P10-8: No section numbers for passes — findings need index

Meta-finding: the spec can now audit itself. Cross-referencing sections
reveals contradictions that weren't visible when each section was written
independently. The RFC is detailed enough to be self-checking.

Ten passes, 80 findings, 3,300+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 13:02:41 +00:00
Snider
a06af7b6ad feat(rfc): Pass Nine — what's missing, what shouldn't be there
P9-1: core/go imports os/exec in app.go — violates its own rule
P9-2: reflect used for service name — magic, fragile on pkg rename
P9-3: No JSON primitive — every consumer imports encoding/json
P9-4: No time primitive — 3 different timestamp formats
P9-5: No ID generation — 3 different patterns (rand, counter, fmt)
P9-6: No validation primitive — path traversal check copy-pasted 3x
P9-7: Error codes exist but nobody uses them
P9-8: No health/observability primitive — go-process has it per-daemon only

Key finding: core/go imports os/exec (P9-1), violating the rule it
established in Section 17. App.Find() uses exec.LookPath — a process
concern that belongs in go-process.

Missing primitives: ID generation, validation, health checks.
Judgment calls: JSON wrapping (maybe noise), time formatting (convention).

Nine passes, 72 findings, 3,100+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:59:45 +00:00
Snider
c847b5d274 feat(rfc): Pass Eight — type safety analysis, 50 hidden panic sites
CRITICAL: 79% of type assertions on Result.Value are bare (no comma-ok).
50 panic sites in core/go, ~100 in core/agent. Every r.Value.(string)
is a deferred panic that (string, error) would catch at compile time.

P8-1: 50/63 assertions bare — panic on wrong type
P8-2: Result is one type for everything — no compile-time safety
P8-3: Message/Query/Task all 'any' — no type routing
P8-4: Option.Value is 'any' — config becomes untyped bag
P8-5: ServiceFor returns (T,bool) not Result — Go generics limitation
P8-6: Fs validatePath returns Result then callers bare-assert string
P8-7: HandleIPCEvents wrong signature silently fails to register
P8-8: The Guardrail Paradox — Core trades compile-time safety for LOC

The fundamental tension: Result reduces LOC but every type assertion
is a deferred panic. Resolution: AX-7 Ugly tests + typed convenience
methods + accept that Result is a runtime contract.

Eight passes, 64 findings, RFC at 2,930+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:56:29 +00:00
Snider
630f1d5d6b feat(rfc): Pass Seven — failure modes, no recovery on most paths
CRITICAL findings:
P7-1: New() returns half-built Core on option failure (no error return)
P7-2: ServiceStartup fails → os.Exit(1) → no cleanup → resource leak
P7-3: ACTION handlers have NO panic recovery (PerformAsync does)
P7-4: Run() has no defer — panic skips ServiceShutdown
P7-5: os.Exit(1) bypasses ALL defers — even if we add them

Additional:
P7-6: Shutdown context timeout stops remaining service cleanup
P7-7: SafeGo exists but nobody uses it — the safety primitive is unwired
P7-8: No circuit breaker — broken handlers called forever

The error path through Core is: log and crash. No rollback, no cleanup,
no recovery. Every failure mode ends in resource leaks or silent state
corruption. The fix is: defer shutdown always, wrap handlers in recover,
stop calling os.Exit from inside Core.

Seven passes, 56 findings, 2,760+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:52:42 +00:00
Snider
f23e4d2be5 feat(rfc): Pass Six — cascade analysis reveals synchronous pipeline blocking
CRITICAL: P6-1 — The entire agent completion pipeline (QA → PR → Verify
→ Merge → Ingest → Poke) runs synchronously nested inside ACTION dispatch.
A slow Forge API call blocks the queue drainer for minutes. This explains
the observed "agents complete but queue doesn't drain" behaviour.

Resolution: pipeline becomes a Task (Section 18), not nested ACTIONs.

P6-2: O(handlers × messages) fanout — every handler checks every message
P6-3: No dispatch context — can't trace nested cascades
P6-4: Monitor half-migrated (ChannelNotifier + ACTION coexist)
P6-5: Three patterns for service-needs-Core (field, ServiceRuntime, param)
P6-6: Message types untyped — any code can emit any message
P6-7: Aggregator pattern (MCP) has no formal Registry support
P6-8: Shutdown order can kill processes before services finish

Six passes, 48 findings. RFC at 2,600+ lines.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:49:57 +00:00
Snider
2167f0c6ab feat(rfc): Pass Five — 8 consumer experience findings
P5-1: ServiceRuntime not used by core/agent — two registration camps exist
P5-2: Register returns Result, OnStartup returns error — consumer confusion
P5-3: No service dependency declaration — implicit order, non-deterministic start
P5-4: HandleIPCEvents auto-discovered via reflect — magic method name
P5-5: Commands registered during OnStartup — invisible timing dependency
P5-6: No service discovery by interface/capability — only lookup by name
P5-7: Factory can see but can't safely USE other services
P5-8: MCP aggregator pattern undocumented — cross-cutting service reads all Actions

Key finding: two camps exist (manual .core vs ServiceRuntime). Both work,
neither documented. HandleIPCEvents is magic — anti-AX.

RFC now 2,436 lines. Five passes, 40 findings.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:46:29 +00:00
Snider
6709b0bb1a feat(rfc): Pass Four — 8 concurrency and performance findings
P4-1: ServiceStartup order non-deterministic (map iteration)
P4-2: ACTION dispatch synchronous and blocking
P4-3: ACTION !OK stops chain (wrong for broadcast)
P4-4: IPC clone-and-iterate safe but undocumented
P4-5: PerformAsync has no backpressure (unlimited goroutines)
P4-6: ConfigVar.Set() has no lock (data race)
P4-7: PerformAsync shutdown TOCTOU race
P4-8: Named lock "srv" shared across all service ops

Key finding: ACTION stopping on !OK is a bug for broadcast semantics.
Registry[T] resolves P4-1 (insertion order) and P4-8 (per-registry locks).

RFC now 2,269 lines. Four passes, 32 findings total.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:43:16 +00:00
Snider
ecd27e3cc9 feat(rfc): Pass Three — 8 spec contradictions found
P3-1: Startable/Stoppable return error, not Result — change to Result
P3-2: Process returns (string,error), Action returns Result — unify on Result
P3-3: Three getter patterns (Result, typed, tuple) — document the two real ones
P3-4: Dual-purpose methods anti-AX — keep as sugar, Registry has explicit verbs
P3-5: error leaks despite Result — accept at Go stdlib boundary, Result at Core
P3-6: Data has overlapping APIs — split mount management from file access
P3-7: Action has no error propagation — inherit PerformAsync's panic recovery
P3-8: Registry.Lock() one-way door — add Seal() for hot-reload (update yes, new no)

RFC now at 2,194 lines. Three passes complete:
- Pass 1: 16 known issues (all resolved)
- Pass 2: 8 architectural findings
- Pass 3: 8 spec contradictions

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:39:27 +00:00
Snider
42fc6fa931 feat(rfc): Pass Two — 8 architectural findings
P2-1: Core struct fully unexported — export bricks, hide safety
P2-2: Fs.root correctly unexported — security boundaries are the exception
P2-3: Config.Settings untyped map[string]any — needs ConfigVar[T] or schema
P2-4: Global assetGroups outside conclave — bootstrap problem, document boundary
P2-5: SysInfo frozen at init() — cached values override test env (known bug)
P2-6: ErrorPanic.onCrash unexported — monitoring can't wire crash handlers
P2-7: Data.mounts unexported — should embed Registry[*Embed]
P2-8: Logging timing gap — global logger unconfigured until New() completes

New rule: export the bricks, hide the safety mechanisms.
Security boundaries (Fs.root) are the ONE exception to Lego Bricks.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:35:04 +00:00
Snider
881c8f2ae8 feat(rfc): versioning model + v0.8.0 requirements checklist
Release model:
- v0.7.x = current stable + mechanical fixes
- v0.8.0 = production: all issues resolved, Sections 17-20 implemented
- v0.8.x patches = process gaps (each one = spec missed something)
- Patch count per release IS the quality metric

v0.8.0 checklist: 16 issues, 4 new sections, AX-7 100%, zero os/exec,
AGENTS.md everywhere. Non-blockers documented (cli, Borg, PHP/TS).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:30:03 +00:00
Snider
59dcbc2a31 feat(rfc): resolve ALL 16 known issues
Pass one complete. All 16 issues now have dispositions:

Resolved (design decisions):
- 1: Naming convention — CamelCase=primitive, UPPERCASE=sugar
- 5: RegisterAction location → solved by Issue 16 split
- 6: serviceRegistry → exported via Registry[T] (Section 20)
- 8: NewRuntime → NOT legacy, it's GUI bridge. Update factory signature.
- 9: CommandLifecycle → three-layer CLI (Cli/cli/go-process)
- 10: Array[T] → guardrail primitive, keep
- 11: ConfigVar[T] → promote to documented primitive
- 12: Ipc → owns Action registry, reads from Registry[T]
- 16: task.go → splits into ipc.go + action.go

Resolved (mechanical fixes):
- 2: MustServiceFor → keep, document startup-only usage
- 3: Embed() → remove (dead code)
- 4: Logging → document boundary (global=bootstrap, Core=runtime)
- 13: Lock allocation → use Registry[T], cache Lock struct
- 14: Startables/Stoppables → return []*Service directly
- 15: Stale comment → fix to match *Core return

Blocked (planned):
- 7: c.Process() → spec'd in Section 17, needs go-process v0.7.0

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:25:59 +00:00
Snider
b130309c3d feat(rfc): resolve Issues 10+11 — Array[T] and ConfigVar[T] as guardrail primitives
Issue 10 (Resolved): Array[T] is a guardrail primitive, not speculative.
Same role as string helpers — forces single codepath, model-proof,
scannable. Ordered counterpart to Registry[T].

Issue 11 (Resolved): ConfigVar[T] promoted to documented primitive.
Solves "was this explicitly set?" tracking for layered config.
Typed counterpart to Option (which is any-typed).

Both follow the guardrail pattern: the primitive exists not because
Go can't do it, but because weaker models (Gemini, Codex) will
reinvent it inline every time — badly. One import, one pattern.

Added primitive taxonomy table showing the full picture:
strings→core.Contains, paths→core.JoinPath, errors→core.E,
maps→Registry[T], slices→Array[T], config→ConfigVar[T]

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:22:10 +00:00
Snider
79fd8c4760 feat(rfc): Section 20 — c.Registry() universal collection primitive
Registry[T] is the brick that all named collections build on:
- map[string]T + mutex + optional locking
- Set/Get/Has/Names/List/Each/Lock/Delete
- c.Registry("services"), c.Registry("actions"), c.Registry("drives")

Resolves Issues 6 + 12:
- serviceRegistry/commandRegistry become exported, embed Registry[T]
- IPC is safe to expose — reads from registry, doesn't own write path
- Registration goes through c.Action(), locking through c.Registry().Lock()

Typed accessors (c.Service, c.Action, c.Drive) are sugar over
c.Registry(name).Get(). Universal query layer on top.

Replaces 5 separate map+mutex+lock implementations with one primitive.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:13:19 +00:00
Snider
5211d97d66 feat(rfc): resolve Issue 16 — task.go splits into ipc.go + action.go
task.go has 6 functions mixing registration and execution:
- RegisterAction/RegisterActions/RegisterTask → ipc.go (registry)
- Perform/PerformAsync/Progress → action.go (execution)

contract.go message types (ActionTaskStarted etc) stay — naming
already correct per Issue 1 convention.

Added AX principles 8-9:
8. Naming encodes architecture (CamelCase=brick, UPPERCASE=sugar)
9. File = concern (one file, one job)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 12:01:39 +00:00
Snider
68b7530072 feat(rfc): resolve Issues 1+12 — naming convention + IPC as registry owner
Issue 1 (Resolved): UPPERCASE vs CamelCase naming convention:
- CamelCase = primitive (the brick): c.Action(), c.Service(), c.Config()
- UPPERCASE = consumer convenience (sugar): c.ACTION(), c.QUERY(), c.PERFORM()
- Current code has this backwards — ACTION is mapped to raw dispatch

Issue 12 (Resolved): IPC owns the Action registry:
- c.IPC() = owns the data (registry, handlers, task flows)
- c.Action() = primitive API for register/invoke/inspect
- c.ACTION() = convenience shortcut for broadcast
- Three layers, one registry — same pattern as Drive/API

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:58:27 +00:00
Snider
7a9f9dfbd1 feat(rfc): Section 19 — c.API() remote stream primitive
HTTP/WebSocket/SSE/MCP are all streams. The transport is irrelevant.

- c.IPC() = local conclave (in-process)
- c.API() = remote streams (cross-machine)
- c.Drive() = connection config (WHERE), c.API() = transport (HOW)
- Protocol handlers register like Actions (permission by registration)
- Remote Action dispatch: "charon:agentic.status" → transparent cross-machine
- Maps current manual HTTP/SSE/MCP code in core/agent to single-line calls
- Full 13-subsystem map documented

Proved by: PHP5 stream lib that replaced curl when certs were broken.
Same principle — depend on stream primitive, not transport library.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:46:36 +00:00
Snider
773e9ee015 feat(rfc): Issue 9 — three-layer CLI architecture (Cli/cli/go-process)
CommandLifecycle replaced with Managed field on Command struct.
Three layers read the same declaration:
- core.Cli() — primitive: basic parsing, runs Action
- core/cli — extension: rich help, completion, daemon management UI
- go-process — extension: PID, health, signals, registry

Command struct is data not behaviour. Services declare,
packages consume. Lifecycle verbs become process Actions.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:40:35 +00:00
Snider
8f7a1223ef feat(rfc): Known Issues 9-16 — recovered ADHD brain dumps
9.  CommandLifecycle — daemon skeleton, never wired to go-process
10. Array[T] — generic collection used nowhere, speculative
11. ConfigVar[T] — typed config var, only used internally
12. Ipc data-only struct — no methods, misleading accessor
13. Lock() allocates wrapper struct on every call
14. Startables/Stoppables return Result instead of []*Service
15. contract.go comment says New() returns Result (stale)
16. task.go mixes execution + registration concerns

Each issue has: what it is, what the intent was, how it relates
to Sections 17-18, and a proposed resolution. These are the
sliding-context ideas saved in quick implementations that need
the care they deserve.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:33:16 +00:00
Snider
76714fa292 feat(rfc): Section 18 — Action and Task execution primitives
Action = named, registered callable. The atomic unit of work.
Task = composition of Actions (chain, parallel, conditional, scheduled).

Key design:
- c.Action("name", handler) registers, c.Action("name").Run() invokes
- Services register actions during OnStartup (same as commands)
- Namespace IS capability map (process.*, agentic.*, brain.*)
- Registration IS permission — no action = no capability
- Current IPC verbs (ACTION/QUERY/PERFORM) become invocation modes
- c.Process() is sugar over process.* actions
- Tasks compose Actions into flows (sequential, parallel, conditional, cron)
- Action registry is queryable — agents inspect capabilities before using

Sections: 18.1-18.10 covering concept, API, registration, permission,
task composition (chain/parallel/conditional/scheduled), IPC mapping,
process integration, and registry inspection.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:24:44 +00:00
Snider
ec17e3da07 feat(rfc): Section 17 — c.Process() primitive spec
Full design spec for process management as Core subsystem:
- 17.1: Primitive concept (interface in core/go, impl in go-process)
- 17.2: Process struct + accessor
- 17.3: Sync execution (Run, RunIn, RunWithEnv)
- 17.4: Async execution (Start + ProcessOptions)
- 17.5: ProcessHandle (IsRunning, Kill, Done, Wait, Info)
- 17.6: IPC messages (ProcessRun/Start/Kill + Started/Output/Exited/Killed)
- 17.7: Permission by registration (no handler = no capability)
- 17.8: Per-package convenience helpers
- 17.9: go-process implementation (IPC handler registration)
- 17.10: Migration path (current → target)

Key insight: registration IS permission. Sandboxed Core without
go-process cannot execute external commands. No config, no tokens,
no capability files — the service exists or it doesn't.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:17:48 +00:00
Snider
f65884075b feat(rfc): add Design Philosophy + Known Issues to API spec
Design Philosophy:
- Core is Lego Bricks — export primitives, reduce downstream LOC
- Export rules: struct fields yes, mutexes no
- Why core/go is minimal (stdlib-only, layers import downward)

Known Issues (8):
1. Dual IPC naming (ACTION vs Action)
2. MustServiceFor uses panic (contradicts Result pattern)
3. Embed() legacy accessor (dead code)
4. Package-level vs Core-level logging (document boundary)
5. RegisterAction in wrong file (task.go vs ipc.go)
6. serviceRegistry unexported (should be Lego brick)
7. No c.Process() accessor (planned)
8. NewRuntime/NewWithFactories legacy (verify usage)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:13:35 +00:00
Snider
1455764e3c feat: add docs/RFC.md — CoreGO API contract specification
Full API spec covering all 16 subsystems: Core container, primitives
(Option/Options/Result), service system, IPC (ACTION/QUERY/PERFORM),
Config, Data, Drive, Fs, CLI, error handling, logging, strings, paths,
utils, locks, ServiceRuntime.

An agent can write a Core service from this document alone.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-25 11:01:58 +00:00
Snider
2d52b83f60 docs: rewrite documentation suite against AX spec
Codex-authored docs covering primitives, commands, messaging,
lifecycle, subsystems, and getting started — all using the current
DTO/Options/Result API with concrete usage examples.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-21 10:05:04 +00:00
Snider
d66ff46312 docs: remove implemented plans, annotate partial ones
18 plan files deleted (absorbed into core.help docs).
4 kept with implementation notes (lint MCP, AltumCode Layer 2).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 08:09:20 +00:00