Help us shape the future of Go! Take the 2026 Go Developer Survey

lifecycle

package
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package lifecycle is wowapi's STATIC provider/lifecycle manifest (backlog B9). It is deliberately NOT a runtime DI container: there is no reflection, no codegen, and no service locator. It is a small, hand-maintained descriptor model — ProviderDescriptor{Provides, Requires, Scope} — that captures the REAL provider graph wired by kernel.New (kernel/kernel.go), app.Boot/moduleContext (app/context.go, app/boot.go), and module.Context (module/module.go), plus a pure-function lint over that manifest that catches the wiring-mistake classes the framework-competitive-architecture- benchmark's "DI / IoC: Static Lifecycle Graph For Go" section calls out.

The manifest is maintained by hand alongside the wiring it describes (there is no generator reading kernel.go via reflection/AST) — Manifest() below IS the source of truth the lint runs over, and CurrentManifest's own test (TestCurrentManifestLintsClean) is the regression net: if a future change to kernel.New/app.Boot/module.Context adds a wiring mistake, either that test or a forgotten manifest update will need updating, keeping the manifest honest by review.

Index

Constants

View Source
const (
	ClassScopeLeak       = "scope_leak"        // (a) process-scoped depends on request-scoped
	ClassRawPool         = "raw_pool"          // (b) module receives a raw pool instead of TxManager
	ClassTenantEscape    = "tenant_escape"     // (c) tenant-scoped service escapes its transaction
	ClassMigrateInAPI    = "migrate_in_api"    // (d) migrate-only service wired into API runtime
	ClassMissingProvider = "missing_provider"  // (e) declared Requires has no matching Provides
	ClassCycle           = "cycle"             // (e) dependency cycle
	ClassDuplicate       = "duplicate_provide" // manifest hygiene: two descriptors with the same Provides
	ClassInvalidScope    = "invalid_scope"     // manifest hygiene: Scope is not one of the five recognized values
)

Violation classes, matching backlog B9's acceptance list verbatim so a reader can cross-reference the backlog item to the check that enforces it.

Variables

This section is empty.

Functions

This section is empty.

Types

type Manifest

type Manifest struct {
	Descriptors []ProviderDescriptor
}

Manifest is an ordered set of descriptors. Order is preserved for stable printing; lint functions are order-independent (they index by Provides).

func CurrentManifest

func CurrentManifest() Manifest

CurrentManifest is the hand-maintained descriptor graph for wowapi's ACTUAL wiring, read from kernel.New (kernel/kernel.go), app.Boot/moduleContext (app/context.go, app/boot.go) and module.Context (module/module.go) as of this package's introduction (backlog B9). It is not generated: whoever adds a field to Kernel/moduleContext/moduleDeps/module.Context should add or update the matching descriptor(s) here in the same change — the CI gate (`wowapi lint lifecycle`, and TestCurrentManifestLintsClean) exists so a forgotten or wrong update fails loudly rather than silently drifting.

Naming convention: "kernel.<Field>" for a Kernel struct field built in kernel.New; "module.Context.<Method>" for an accessor module.Context exposes (all of which are APIRuntime: true, since module.Register runs in every product's api/worker boot path).

func (Manifest) ByProvides

func (m Manifest) ByProvides() map[string]ProviderDescriptor

ByProvides indexes the manifest's descriptors by their Provides name. Behavior is undefined (last-wins) if two descriptors share a Provides name — checkDuplicateProvides reports that as a violation.

func (Manifest) Print

func (m Manifest) Print() string

Print renders the manifest as a stable, human-readable table (used by `wowapi lint lifecycle` and tests).

func (Manifest) Sorted

func (m Manifest) Sorted() []ProviderDescriptor

Sorted returns a copy of the descriptors sorted by Provides, for deterministic printing/diffing.

type ProviderDescriptor

type ProviderDescriptor struct {
	// Provides is the unique name of the capability this descriptor wires,
	// e.g. "kernel.Pool" or "module.Context.Tx". Conventionally
	// "<owner>.<FieldOrMethod>" matching the real Go identifier so the
	// manifest stays traceable to kernel.go/context.go/module.go.
	Provides string
	// Requires lists the Provides names this descriptor's construction
	// depends on. Every entry must match another descriptor's Provides (lint
	// class (e): missing provider) and must not form a cycle.
	Requires []string
	// Scope is this descriptor's lifetime.
	Scope Scope
	// RawPool marks a descriptor that hands out an unwrapped *pgxpool.Pool
	// (or equivalent raw connection) rather than a TxManager/TenantDB. Lint
	// class (b) flags any module-facing descriptor with this set.
	RawPool bool
	// TenantScoped marks a descriptor whose value must not outlive the
	// tenant transaction that produced it (a database.TenantDB or something
	// derived from one). Lint class (c) flags such a descriptor with a
	// Requires edge FROM a wider-scoped (process/request) descriptor that
	// would let the value escape its transaction.
	TenantScoped bool
	// APIRuntime marks a descriptor that is wired into the api/worker
	// runtime module.Context surface (i.e. reachable from a module's
	// Register). Lint class (d) flags a migrate-scoped descriptor with
	// APIRuntime set — a migrate-only service must never be wired into a
	// process that serves API/worker traffic.
	APIRuntime bool
}

ProviderDescriptor describes one provided value/capability in the wiring graph: what it provides, what it requires (by Provides name of another descriptor), and the scope it is valid at.

type Scope

type Scope string

Scope is the lifetime a provided value is valid for. Mirrors the benchmark doc's recommended Go-native shape (framework-competitive-architecture- benchmark.md, "DI / IoC: Static Lifecycle Graph For Go").

const (
	// ScopeProcess: constructed once in kernel.New, lives for the process
	// lifetime (pools, registries, evaluators, kernel services).
	ScopeProcess Scope = "process"
	// ScopeRequest: constructed per inbound HTTP request (module.Context
	// accessors handed to Module.Register are process-scoped services, but
	// request-handling code that consumes them operates per-request).
	ScopeRequest Scope = "request"
	// ScopeTenantTx: valid only for the lifetime of one tenant-bound
	// transaction opened via database.TxManager.WithTenant/WithTenantRO
	// (database.TenantDB). Must never escape the callback that receives it.
	ScopeTenantTx Scope = "tenant_tx"
	// ScopeJob: constructed for one worker job execution.
	ScopeJob Scope = "job"
	// ScopeMigrate: valid only in the migrate process (privileged DDL
	// connection, app.SkipRLSEnforcementCheck). Must never be wired into a
	// process that serves API/worker runtime traffic.
	ScopeMigrate Scope = "migrate"
)

type Violation

type Violation struct {
	Class    string
	Provides string
	Message  string
}

Violation is one lint finding. Class identifies which failure category (a-e, matching the backlog B9 acceptance list) so callers/tests can filter or count by class; Provides names the offending descriptor; Message is the human-readable detail.

func Lint

func Lint(m Manifest) []Violation

Lint runs every check against m and returns ALL violations found, sorted for deterministic output — mirroring the errs-accumulate pattern used by kernel/config.Framework.Validate and kernel/rules.Registry.Err (collect everything, never stop at the first problem).

func (Violation) String

func (v Violation) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL