capability

package
v0.0.0-...-043add5 Latest Latest
Warning

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

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package capability defines GoCell capability providers: assembly-level shared infrastructure resources (postgres pool, redis client, ...) provisioned once by the composition root and injected into every consuming cell module.

Why assembly-level (not per-cell)

A capability is a fx.Supply-shaped shared value, not a per-cell constructor. The composition root provisions postgres pool(s) / one redis client and injects them into every consuming cell module via the sealed PGSet resolver:

  • Colocated topology: one pool serves all cells; every ForCell call returns the same PGProvider (Sole() reports true). This preserves the single-pool
  • LIFO-shutdown invariant and the one-outbox-table / one-relay model.
  • Split topology (#2341): N distinct-DSN pools are provisioned, one per distinct DSN group. Each cell module calls ForCell(cellID) to obtain its own pool's PGProvider; Sole() returns (nil, false). One relay per pool drains that pool's outbox traffic.

Redis is always single-instance (no per-cell Redis today). See ADR docs/architecture/202605251500-adr-capability-provider-interface.md.

Layering: runtime/capability never imports adapters/

runtime/ may depend only on kernel/ + pkg/ (CLAUDE.md). So the provider interfaces are expressed over kernel types (persistence.TxRunner, outbox.Writer) plus a deliberate `any` typed-erasure seam (DB() / Client()) for the raw adapter handle. The `any` is type-asserted exactly once, in the consumer site inside cmd/* (which may import adapters/).

Sealed construction (AI-robust: upstream Hard)

PGProvider / RedisProvider carry an unexported marker method, so they can only be implemented inside this package. The concrete impls (pgProvider / redisProvider) are private; NewPGProvider / NewRedisProvider are the sole construction paths. A cell module cannot fabricate a bypass provider — it must consume the injected one. This is the upstream-Hard half of the funnel: Go's type system makes a forged provider unrepresentable outside this package.

Funnel closure (downstream Medium)

The downstream half is archtest CAPABILITY-PROVIDER-FUNNEL-01 (tools/archtest/capability_provider_funnel_test.go): a type-aware caller allowlist that bans the shared-infrastructure constructors (adapters/postgres.NewPool / NewTxManager / NewOutboxWriter, adapters/redis.NewClient) anywhere except the single provisioning site cmd/corebundle/cap_wiring.go. Per-cell / per-role derivations that take an already-acquired handle (NewSessionStore / NewLedgerStore / NewOutboxStore / NewCache / NewRedisDriver / …) are intentionally NOT banned.

Rating: upstream Hard (sealed) + downstream Medium (archtest caller-allowlist, not compile-time) — an allowed transition form per ai-robust.md §"Funnel 双向锁评级". The downstream→Hard upgrade is tracked at gh issue #988. The blind-spot inventory lives in that archtest's package godoc, not duplicated here.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Kind

type Kind string

Kind names an assembly-level shared infrastructure capability. Cells declare what they consume via cell.yaml `requires`; the assembly's provisioned set is the derived union of its cells' requires (Design Y, #855 — see kernel/assembly.GenerateModulesGen). The closed value set below is mirrored by the cell.schema.json `requires` enum (kept in lockstep by kernel/metadata/schemas TestSchemaConstantsMatchSchemaLiterals). Unknown or duplicate values are rejected by `gocell validate` governance rule FMT-36 at validation time — not at parse time: ParseFS stays lenient, matching Kubernetes admission-layer enum validation rather than parse-time rejection.

const (
	// Postgres is the shared postgres pool (TxManager + OutboxWriter + DB).
	Postgres Kind = "postgres"
	// Redis is the shared redis client.
	Redis Kind = "redis"
	// RabbitMQ is recognized by the enum but has NO provider / provisioning path
	// yet: there is no RabbitMQProvider and cap_wiring's provisionCapabilities has
	// no rabbitmq case, so declaring `requires: [rabbitmq]` in a cell.yaml passes
	// FMT-36 + codegen but fails fast at provisionCapabilities' default branch. It stays in
	// the enum as recognized forward vocabulary; a real AMQP-shared-connection
	// assembly must land the RabbitMQProvider + provisioning atomically.
	RabbitMQ Kind = "rabbitmq"
)

type PGInstance

type PGInstance struct {
	Provider PGProvider
	Cells    []string
}

PGInstance pairs one pool's provider with the cells it serves. The composition root builds one per distinct-DSN pool (cellmodules/percellpg.Resolve groups the cells); cells across instances must be disjoint.

type PGProvider

type PGProvider interface {
	// TxManager returns the shared transactional runner bound to the pool.
	TxManager() persistence.TxRunner
	// OutboxWriter returns the transactional outbox writer.
	OutboxWriter() outbox.Writer
	// DB returns the raw pool handle (*adapterpg.Pool.DB()) as any. The single
	// type-assertion lives in the cmd/* consumer; runtime/capability stays adapter-free.
	DB() any
	// contains filtered or unexported methods
}

PGProvider is the sealed handle to the assembly's single postgres pool. It is implementable only inside package capability (unexported marker isPGProvider); the sole construction path is NewPGProvider. Consumers receive an injected PGProvider and must not construct adapter primitives themselves (CAPABILITY-PROVIDER-FUNNEL-01).

func NewPGProvider

func NewPGProvider(tx persistence.TxRunner, writer outbox.Writer, db any) PGProvider

NewPGProvider wraps the composition-root-constructed postgres primitives into the sealed PGProvider. tx and writer are kernel-typed; db is the raw *adapterpg.Pool.DB() handle passed as any so this package never imports adapters/. Called only from the assembly wiring site (cmd/<id>/cap_wiring.go).

type PGSet

type PGSet interface {
	// ForCell returns the postgres provider for cellID, or a fail-closed error if
	// the cell has no provisioned pool (never a silent nil).
	ForCell(cellID string) (PGProvider, error)
	// Sole returns (provider, true) iff the assembly is colocated (exactly one
	// distinct pool serving every cell). In split topology it returns (nil, false).
	// It is the SANCTIONED single accessor for assembly-wide consumers that have no
	// "cell" dimension — notably the CQRS projection harness, whose journal
	// global_seq is per-pool and therefore incomparable across a split fan-out, so
	// it MUST fail closed when Sole reports false.
	Sole() (PGProvider, bool)
	// contains filtered or unexported methods
}

PGSet is the per-cell postgres provider resolver injected on composition.SharedDeps (#2341). It replaces the former single SharedDeps.PG PGProvider so each cell module resolves ITS pool's provider via ForCell(cellID) — colocated assemblies map every cell to one shared provider (one pool); split assemblies map each cell to its own pool's provider (N pools, each driven by its own relay keyed by InfraInstanceKey).

It is sealed (unexported marker isPGSet; sole constructor NewPGSet) so the per-instance fan-out cannot be forged outside the composition root, and ForCell fails closed on an unknown cell rather than returning a silent nil. memory topology leaves SharedDeps.PG nil — cell modules take their in-memory path.

func NewPGSet

func NewPGSet(instances []PGInstance) (PGSet, error)

NewPGSet builds the sealed per-cell provider resolver from the per-instance providers. It fails closed on a wiring bug — a nil provider, an instance serving no cells, or a cell mapped to two pools — rather than building a half-wired set. Sole() reports true iff there is exactly one instance (colocated). Called only from the assembly wiring site (cmd/<id>/cap_wiring.go).

A nil or empty instances slice is valid by design: it produces an empty set where every ForCell call returns an error (fail-closed) and Sole() returns (nil, false). This is the memory-topology path where no postgres pool is provisioned; cell modules take their in-memory repository path instead.

type RedisProvider

type RedisProvider interface {
	// Client returns the raw redis client (*adapterredis.Client) as any. The
	// single type-assertion lives in the cmd/* consumer.
	Client() any
	// contains filtered or unexported methods
}

RedisProvider is the sealed handle to the assembly's shared redis client. Implementable only inside package capability; sole construction path NewRedisProvider.

func NewRedisProvider

func NewRedisProvider(client any) RedisProvider

NewRedisProvider wraps the composition-root-constructed redis client into the sealed RedisProvider. client is the raw *adapterredis.Client passed as any.

Jump to

Keyboard shortcuts

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