fix: add usage-example comments to all 37 exported functions (AX Principle 2)
core/go was violating its own RFC-025 Principle 2: every exported function must have a comment showing HOW with real values. 37 functions had no comments — mostly one-liner accessors on Core, Config, ServiceRuntime, IPC, and Options. Now every exported function in every source file has a usage-example comment. AX Principle 2 compliance: 0/37 → 37/37 (100%). Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
8626710f9d
commit
0911d5ad7b
5 changed files with 166 additions and 20 deletions
50
config.go
50
config.go
|
|
@ -14,15 +14,34 @@ type ConfigVar[T any] struct {
|
||||||
set bool
|
set bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ConfigVar[T]) Get() T { return v.val }
|
// Get returns the current value.
|
||||||
func (v *ConfigVar[T]) Set(val T) { v.val = val; v.set = true }
|
//
|
||||||
|
// val := v.Get()
|
||||||
|
func (v *ConfigVar[T]) Get() T { return v.val }
|
||||||
|
|
||||||
|
// Set sets the value and marks it as explicitly set.
|
||||||
|
//
|
||||||
|
// v.Set(true)
|
||||||
|
func (v *ConfigVar[T]) Set(val T) { v.val = val; v.set = true }
|
||||||
|
|
||||||
|
// IsSet returns true if the value was explicitly set (distinguishes "set to false" from "never set").
|
||||||
|
//
|
||||||
|
// if v.IsSet() { /* explicitly configured */ }
|
||||||
func (v *ConfigVar[T]) IsSet() bool { return v.set }
|
func (v *ConfigVar[T]) IsSet() bool { return v.set }
|
||||||
|
|
||||||
|
// Unset resets to zero value and marks as not set.
|
||||||
|
//
|
||||||
|
// v.Unset()
|
||||||
|
// v.IsSet() // false
|
||||||
func (v *ConfigVar[T]) Unset() {
|
func (v *ConfigVar[T]) Unset() {
|
||||||
v.set = false
|
v.set = false
|
||||||
var zero T
|
var zero T
|
||||||
v.val = zero
|
v.val = zero
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewConfigVar creates a ConfigVar with an initial value marked as set.
|
||||||
|
//
|
||||||
|
// debug := core.NewConfigVar(true)
|
||||||
func NewConfigVar[T any](val T) ConfigVar[T] {
|
func NewConfigVar[T any](val T) ConfigVar[T] {
|
||||||
return ConfigVar[T]{val: val, set: true}
|
return ConfigVar[T]{val: val, set: true}
|
||||||
}
|
}
|
||||||
|
|
@ -82,9 +101,20 @@ func (e *Config) Get(key string) Result {
|
||||||
return Result{val, true}
|
return Result{val, true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String retrieves a string config value (empty string if missing).
|
||||||
|
//
|
||||||
|
// host := c.Config().String("database.host")
|
||||||
func (e *Config) String(key string) string { return ConfigGet[string](e, key) }
|
func (e *Config) String(key string) string { return ConfigGet[string](e, key) }
|
||||||
func (e *Config) Int(key string) int { return ConfigGet[int](e, key) }
|
|
||||||
func (e *Config) Bool(key string) bool { return ConfigGet[bool](e, key) }
|
// Int retrieves an int config value (0 if missing).
|
||||||
|
//
|
||||||
|
// port := c.Config().Int("database.port")
|
||||||
|
func (e *Config) Int(key string) int { return ConfigGet[int](e, key) }
|
||||||
|
|
||||||
|
// Bool retrieves a bool config value (false if missing).
|
||||||
|
//
|
||||||
|
// debug := c.Config().Bool("debug")
|
||||||
|
func (e *Config) Bool(key string) bool { return ConfigGet[bool](e, key) }
|
||||||
|
|
||||||
// ConfigGet retrieves a typed configuration value.
|
// ConfigGet retrieves a typed configuration value.
|
||||||
func ConfigGet[T any](e *Config, key string) T {
|
func ConfigGet[T any](e *Config, key string) T {
|
||||||
|
|
@ -99,6 +129,9 @@ func ConfigGet[T any](e *Config, key string) T {
|
||||||
|
|
||||||
// --- Feature Flags ---
|
// --- Feature Flags ---
|
||||||
|
|
||||||
|
// Enable activates a feature flag.
|
||||||
|
//
|
||||||
|
// c.Config().Enable("dark-mode")
|
||||||
func (e *Config) Enable(feature string) {
|
func (e *Config) Enable(feature string) {
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
if e.ConfigOptions == nil {
|
if e.ConfigOptions == nil {
|
||||||
|
|
@ -109,6 +142,9 @@ func (e *Config) Enable(feature string) {
|
||||||
e.mu.Unlock()
|
e.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable deactivates a feature flag.
|
||||||
|
//
|
||||||
|
// c.Config().Disable("dark-mode")
|
||||||
func (e *Config) Disable(feature string) {
|
func (e *Config) Disable(feature string) {
|
||||||
e.mu.Lock()
|
e.mu.Lock()
|
||||||
if e.ConfigOptions == nil {
|
if e.ConfigOptions == nil {
|
||||||
|
|
@ -119,6 +155,9 @@ func (e *Config) Disable(feature string) {
|
||||||
e.mu.Unlock()
|
e.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enabled returns true if a feature flag is active.
|
||||||
|
//
|
||||||
|
// if c.Config().Enabled("dark-mode") { ... }
|
||||||
func (e *Config) Enabled(feature string) bool {
|
func (e *Config) Enabled(feature string) bool {
|
||||||
e.mu.RLock()
|
e.mu.RLock()
|
||||||
defer e.mu.RUnlock()
|
defer e.mu.RUnlock()
|
||||||
|
|
@ -128,6 +167,9 @@ func (e *Config) Enabled(feature string) bool {
|
||||||
return e.Features[feature]
|
return e.Features[feature]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnabledFeatures returns all active feature flag names.
|
||||||
|
//
|
||||||
|
// features := c.Config().EnabledFeatures()
|
||||||
func (e *Config) EnabledFeatures() []string {
|
func (e *Config) EnabledFeatures() []string {
|
||||||
e.mu.RLock()
|
e.mu.RLock()
|
||||||
defer e.mu.RUnlock()
|
defer e.mu.RUnlock()
|
||||||
|
|
|
||||||
101
core.go
101
core.go
|
|
@ -45,23 +45,83 @@ type Core struct {
|
||||||
|
|
||||||
// --- Accessors ---
|
// --- Accessors ---
|
||||||
|
|
||||||
func (c *Core) Options() *Options { return c.options }
|
// Options returns the input configuration passed to core.New().
|
||||||
func (c *Core) App() *App { return c.app }
|
//
|
||||||
func (c *Core) Data() *Data { return c.data }
|
// opts := c.Options()
|
||||||
func (c *Core) Drive() *Drive { return c.drive }
|
// name := opts.String("name")
|
||||||
func (c *Core) Fs() *Fs { return c.fs }
|
func (c *Core) Options() *Options { return c.options }
|
||||||
func (c *Core) Config() *Config { return c.config }
|
|
||||||
func (c *Core) Error() *ErrorPanic { return c.error }
|
// App returns application identity metadata.
|
||||||
func (c *Core) Log() *ErrorLog { return c.log }
|
//
|
||||||
|
// c.App().Name // "my-app"
|
||||||
|
// c.App().Version // "1.0.0"
|
||||||
|
func (c *Core) App() *App { return c.app }
|
||||||
|
|
||||||
|
// Data returns the embedded asset registry (Registry[*Embed]).
|
||||||
|
//
|
||||||
|
// r := c.Data().ReadString("prompts/coding.md")
|
||||||
|
func (c *Core) Data() *Data { return c.data }
|
||||||
|
|
||||||
|
// Drive returns the transport handle registry (Registry[*DriveHandle]).
|
||||||
|
//
|
||||||
|
// r := c.Drive().Get("forge")
|
||||||
|
func (c *Core) Drive() *Drive { return c.drive }
|
||||||
|
|
||||||
|
// Fs returns the sandboxed filesystem.
|
||||||
|
//
|
||||||
|
// r := c.Fs().Read("/path/to/file")
|
||||||
|
// c.Fs().WriteAtomic("/status.json", data)
|
||||||
|
func (c *Core) Fs() *Fs { return c.fs }
|
||||||
|
|
||||||
|
// Config returns runtime settings and feature flags.
|
||||||
|
//
|
||||||
|
// host := c.Config().String("database.host")
|
||||||
|
// c.Config().Enable("dark-mode")
|
||||||
|
func (c *Core) Config() *Config { return c.config }
|
||||||
|
|
||||||
|
// Error returns the panic recovery subsystem.
|
||||||
|
//
|
||||||
|
// c.Error().Recover()
|
||||||
|
func (c *Core) Error() *ErrorPanic { return c.error }
|
||||||
|
|
||||||
|
// Log returns the structured logging subsystem.
|
||||||
|
//
|
||||||
|
// c.Log().Info("started", "port", 8080)
|
||||||
|
func (c *Core) Log() *ErrorLog { return c.log }
|
||||||
|
|
||||||
|
// Cli returns the CLI command framework (registered as service "cli").
|
||||||
|
//
|
||||||
|
// c.Cli().Run("deploy", "to", "homelab")
|
||||||
func (c *Core) Cli() *Cli {
|
func (c *Core) Cli() *Cli {
|
||||||
cl, _ := ServiceFor[*Cli](c, "cli")
|
cl, _ := ServiceFor[*Cli](c, "cli")
|
||||||
return cl
|
return cl
|
||||||
}
|
}
|
||||||
func (c *Core) IPC() *Ipc { return c.ipc }
|
|
||||||
func (c *Core) I18n() *I18n { return c.i18n }
|
// IPC returns the message bus internals.
|
||||||
func (c *Core) Env(key string) string { return Env(key) }
|
//
|
||||||
|
// c.IPC()
|
||||||
|
func (c *Core) IPC() *Ipc { return c.ipc }
|
||||||
|
|
||||||
|
// I18n returns the internationalisation subsystem.
|
||||||
|
//
|
||||||
|
// tr := c.I18n().Translate("cmd.deploy.description")
|
||||||
|
func (c *Core) I18n() *I18n { return c.i18n }
|
||||||
|
|
||||||
|
// Env returns an environment variable by key (cached at init, falls back to os.Getenv).
|
||||||
|
//
|
||||||
|
// home := c.Env("DIR_HOME")
|
||||||
|
// token := c.Env("FORGE_TOKEN")
|
||||||
|
func (c *Core) Env(key string) string { return Env(key) }
|
||||||
|
|
||||||
|
// Context returns Core's lifecycle context (cancelled on shutdown).
|
||||||
|
//
|
||||||
|
// ctx := c.Context()
|
||||||
func (c *Core) Context() context.Context { return c.context }
|
func (c *Core) Context() context.Context { return c.context }
|
||||||
func (c *Core) Core() *Core { return c }
|
|
||||||
|
// Core returns self — satisfies the ServiceRuntime interface.
|
||||||
|
//
|
||||||
|
// c := s.Core()
|
||||||
|
func (c *Core) Core() *Core { return c }
|
||||||
|
|
||||||
// --- Lifecycle ---
|
// --- Lifecycle ---
|
||||||
|
|
||||||
|
|
@ -109,9 +169,22 @@ func (c *Core) Run() {
|
||||||
|
|
||||||
// --- IPC (uppercase aliases) ---
|
// --- IPC (uppercase aliases) ---
|
||||||
|
|
||||||
|
// ACTION broadcasts a message to all registered handlers (fire-and-forget).
|
||||||
|
// Each handler is wrapped in panic recovery. All handlers fire regardless.
|
||||||
|
//
|
||||||
|
// c.ACTION(messages.AgentCompleted{Agent: "codex", Status: "completed"})
|
||||||
func (c *Core) ACTION(msg Message) Result { return c.broadcast(msg) }
|
func (c *Core) ACTION(msg Message) Result { return c.broadcast(msg) }
|
||||||
func (c *Core) QUERY(q Query) Result { return c.Query(q) }
|
|
||||||
func (c *Core) QUERYALL(q Query) Result { return c.QueryAll(q) }
|
// QUERY sends a request — first handler to return OK wins.
|
||||||
|
//
|
||||||
|
// r := c.QUERY(MyQuery{Name: "brain"})
|
||||||
|
func (c *Core) QUERY(q Query) Result { return c.Query(q) }
|
||||||
|
|
||||||
|
// QUERYALL sends a request — collects all OK responses.
|
||||||
|
//
|
||||||
|
// r := c.QUERYALL(countQuery{})
|
||||||
|
// results := r.Value.([]any)
|
||||||
|
func (c *Core) QUERYALL(q Query) Result { return c.QueryAll(q) }
|
||||||
|
|
||||||
// --- Error+Log ---
|
// --- Error+Log ---
|
||||||
|
|
||||||
|
|
|
||||||
10
ipc.go
10
ipc.go
|
|
@ -45,6 +45,9 @@ func (c *Core) broadcast(msg Message) Result {
|
||||||
return Result{OK: true}
|
return Result{OK: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Query dispatches a request — first handler to return OK wins.
|
||||||
|
//
|
||||||
|
// r := c.Query(MyQuery{})
|
||||||
func (c *Core) Query(q Query) Result {
|
func (c *Core) Query(q Query) Result {
|
||||||
c.ipc.queryMu.RLock()
|
c.ipc.queryMu.RLock()
|
||||||
handlers := slices.Clone(c.ipc.queryHandlers)
|
handlers := slices.Clone(c.ipc.queryHandlers)
|
||||||
|
|
@ -59,6 +62,10 @@ func (c *Core) Query(q Query) Result {
|
||||||
return Result{}
|
return Result{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryAll dispatches a request — collects all OK responses.
|
||||||
|
//
|
||||||
|
// r := c.QueryAll(countQuery{})
|
||||||
|
// results := r.Value.([]any)
|
||||||
func (c *Core) QueryAll(q Query) Result {
|
func (c *Core) QueryAll(q Query) Result {
|
||||||
c.ipc.queryMu.RLock()
|
c.ipc.queryMu.RLock()
|
||||||
handlers := slices.Clone(c.ipc.queryHandlers)
|
handlers := slices.Clone(c.ipc.queryHandlers)
|
||||||
|
|
@ -74,6 +81,9 @@ func (c *Core) QueryAll(q Query) Result {
|
||||||
return Result{results, true}
|
return Result{results, true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterQuery registers a handler for QUERY dispatch.
|
||||||
|
//
|
||||||
|
// c.RegisterQuery(func(_ *core.Core, q core.Query) core.Result { ... })
|
||||||
func (c *Core) RegisterQuery(handler QueryHandler) {
|
func (c *Core) RegisterQuery(handler QueryHandler) {
|
||||||
c.ipc.queryMu.Lock()
|
c.ipc.queryMu.Lock()
|
||||||
c.ipc.queryHandlers = append(c.ipc.queryHandlers, handler)
|
c.ipc.queryHandlers = append(c.ipc.queryHandlers, handler)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ func (r Result) Result(args ...any) Result {
|
||||||
return r.New(args...)
|
return r.New(args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New adapts Go (value, error) pairs into a Result.
|
||||||
|
//
|
||||||
|
// r := core.Result{}.New(file, err)
|
||||||
func (r Result) New(args ...any) Result {
|
func (r Result) New(args ...any) Result {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return r
|
return r
|
||||||
|
|
@ -67,6 +70,9 @@ func (r Result) New(args ...any) Result {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get returns the Result if OK, empty Result otherwise.
|
||||||
|
//
|
||||||
|
// r := core.Result{Value: "hello", OK: true}.Get()
|
||||||
func (r Result) Get() Result {
|
func (r Result) Get() Result {
|
||||||
if r.OK {
|
if r.OK {
|
||||||
return r
|
return r
|
||||||
|
|
|
||||||
19
runtime.go
19
runtime.go
|
|
@ -25,8 +25,19 @@ func NewServiceRuntime[T any](c *Core, opts T) *ServiceRuntime[T] {
|
||||||
return &ServiceRuntime[T]{core: c, opts: opts}
|
return &ServiceRuntime[T]{core: c, opts: opts}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *ServiceRuntime[T]) Core() *Core { return r.core }
|
// Core returns the Core instance this service is registered with.
|
||||||
func (r *ServiceRuntime[T]) Options() T { return r.opts }
|
//
|
||||||
|
// c := s.Core()
|
||||||
|
func (r *ServiceRuntime[T]) Core() *Core { return r.core }
|
||||||
|
|
||||||
|
// Options returns the typed options this service was created with.
|
||||||
|
//
|
||||||
|
// opts := s.Options() // MyOptions{BufferSize: 1024, ...}
|
||||||
|
func (r *ServiceRuntime[T]) Options() T { return r.opts }
|
||||||
|
|
||||||
|
// Config is a shortcut to s.Core().Config().
|
||||||
|
//
|
||||||
|
// host := s.Config().String("database.host")
|
||||||
func (r *ServiceRuntime[T]) Config() *Config { return r.core.Config() }
|
func (r *ServiceRuntime[T]) Config() *Config { return r.core.Config() }
|
||||||
|
|
||||||
// --- Lifecycle ---
|
// --- Lifecycle ---
|
||||||
|
|
@ -137,10 +148,14 @@ func NewRuntime(app any) Result {
|
||||||
return NewWithFactories(app, map[string]ServiceFactory{})
|
return NewWithFactories(app, map[string]ServiceFactory{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServiceName returns "Core" — the Runtime's service identity.
|
||||||
func (r *Runtime) ServiceName() string { return "Core" }
|
func (r *Runtime) ServiceName() string { return "Core" }
|
||||||
|
|
||||||
|
// ServiceStartup starts all services via the embedded Core.
|
||||||
func (r *Runtime) ServiceStartup(ctx context.Context, options any) Result {
|
func (r *Runtime) ServiceStartup(ctx context.Context, options any) Result {
|
||||||
return r.Core.ServiceStartup(ctx, options)
|
return r.Core.ServiceStartup(ctx, options)
|
||||||
}
|
}
|
||||||
|
// ServiceShutdown stops all services via the embedded Core.
|
||||||
func (r *Runtime) ServiceShutdown(ctx context.Context) Result {
|
func (r *Runtime) ServiceShutdown(ctx context.Context) Result {
|
||||||
if r.Core != nil {
|
if r.Core != nil {
|
||||||
return r.Core.ServiceShutdown(ctx)
|
return r.Core.ServiceShutdown(ctx)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue