From b95e265d28bc0dbbb515d52c93ae8ace16f2bda9 Mon Sep 17 00:00:00 2001 From: "user.email" Date: Wed, 25 Mar 2026 17:48:47 +0000 Subject: [PATCH] =?UTF-8?q?fix(rfc-025):=20pass=203=20=E2=80=94=20Draft?= =?UTF-8?q?=E2=86=92Active,=20ServiceRuntime=20consistency,=20security=20c?= =?UTF-8?q?allout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Status: Draft → Active (10 principles, validated, governs ecosystem) - Adoption: exec.Command → c.Process() (not go-process) - Command Registration: uses OnStartup + s.Core() (ServiceRuntime pattern) - Process example: s.core → s.Core() (ServiceRuntime, not manual field) - Process anti-pattern: added "path traversal risk" + "no entitlement" callout - Added security note: AX model IS the security model — Actions gate through entitlements Co-Authored-By: Virgil --- docs/specs/RFC-025-AGENT-EXPERIENCE.md | 31 ++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/specs/RFC-025-AGENT-EXPERIENCE.md b/docs/specs/RFC-025-AGENT-EXPERIENCE.md index 43c4ade..f102237 100644 --- a/docs/specs/RFC-025-AGENT-EXPERIENCE.md +++ b/docs/specs/RFC-025-AGENT-EXPERIENCE.md @@ -1,6 +1,6 @@ # RFC-025: Agent Experience (AX) Design Principles -- **Status:** Draft +- **Status:** Active - **Authors:** Snider, Cladius - **Date:** 2026-03-25 - **Applies to:** All Core ecosystem packages (CoreGO, CorePHP, CoreTS, core-agent) @@ -424,15 +424,16 @@ func Register(c *core.Core) (*MyService, error) { ```go // AX-native: extracted methods, testable without CLI -func (s *PrepSubsystem) registerForgeCommands() { - c := s.core - c.Command("issue/get", core.Command{Description: "Get a Forge issue", Action: s.cmdIssueGet}) - c.Command("issue/list", core.Command{Description: "List Forge issues", Action: s.cmdIssueList}) +func (s *MyService) OnStartup(ctx context.Context) core.Result { + c := s.Core() + c.Command("issue/get", core.Command{Action: s.cmdIssueGet}) + c.Command("issue/list", core.Command{Action: s.cmdIssueList}) + c.Action("forge.issue.get", s.handleIssueGet) + return core.Result{OK: true} } -func (s *PrepSubsystem) cmdIssueGet(opts core.Options) core.Result { - org, repo, num := parseForgeArgs(opts) - // ... testable business logic +func (s *MyService) cmdIssueGet(opts core.Options) core.Result { + // testable business logic — no closure, no CLI dependency } // Not AX: closures that can only be tested via CLI integration @@ -447,22 +448,24 @@ c.Command("issue/get", core.Command{ ```go // AX-native: Core Process primitive, testable with mock handler -func (s *PrepSubsystem) getGitLog(repoPath string) string { - r := s.core.Process().RunIn(context.Background(), repoPath, "git", "log", "--oneline", "-20") +func (s *MyService) getGitLog(repoPath string) string { + r := s.Core().Process().RunIn(context.Background(), repoPath, "git", "log", "--oneline", "-20") if !r.OK { return "" } return core.Trim(r.Value.(string)) } -// Not AX: raw exec.Command, untestable without real git -func (s *PrepSubsystem) getGitLog(repoPath string) string { +// Not AX: raw exec.Command — untestable, no entitlement check, path traversal risk +func (s *MyService) getGitLog(repoPath string) string { cmd := exec.Command("git", "log", "--oneline", "-20") - cmd.Dir = repoPath + cmd.Dir = repoPath // user-controlled path goes directly to OS output, err := cmd.Output() if err != nil { return "" } return strings.TrimSpace(string(output)) } ``` +The AX-native version routes through `c.Process()` → named Action → entitlement check. The non-AX version passes user input directly to `os/exec` with no permission gate. + ### Permission Gating ```go @@ -495,7 +498,7 @@ AX applies to all new code in the Core ecosystem. Existing code migrates increme Priority order: 1. **Public APIs** (package-level functions, struct constructors) 2. **Test naming** (AX-7 Good/Bad/Ugly convention) -3. **Process execution** (exec.Command → go-process) +3. **Process execution** (exec.Command → `c.Process()`) 4. **File structure** (path naming, template locations) 5. **Internal fields** (struct field names, local variables)