cellgen

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: 27 Imported by: 0

Documentation

Overview

Package cellgen renders cell_gen.go and slice_gen.go from cell.yaml / slice.yaml metadata. It plugs into the tools/codegen framework: yaml → CellGenSpec / SliceGenSpec → text/template → goimports → disk.

It is the first codegen adapter; future adapters (contract DTO, marker reverse-gen) will live alongside under tools/codegen/.

Usage

Entry point: cellgen.Generate. BuildCellSpec and BuildSliceSpec are exposed for unit testing the spec-building logic in isolation; production callers should use Generate.

stage_render.go — ephemeral staging dir helpers for cross-stage scaffold.

INVARIANT: SCAFFOLD-CELL-BUNDLE-CROSS-STAGE-PLAN-MERGE-01

materializeSkeletonStage and appendDerivedCodegen together implement the ephemeral-staging pattern that merges skeleton + codegen-derived artifacts into a single pathsafe.WritePlannedFiles plan for PlanCellBundleScaffold.

Staging strategy (zero new OS-ban exemptions):

  • os.MkdirTemp / os.RemoveAll are NOT in the SCAFFOLD-WRITE-FUNNEL-01 banned set (MkdirAll / WriteFile / Mkdir / Create / OpenFile); they only manage the temporary directory lifetime.
  • Skeleton files are written into the staging root via pathsafe.WritePlannedFiles itself — staging USES the funnel, not bypass.
  • The shared error-response schema is copied into staging as a PlannedFile so contractgen's relative SchemaRef resolution can find it.
  • Derived artifacts are rendered in-memory against the staging tree and rebased onto realRoot via planDerivedArtifact, which restores the governance.IsGoCellGenerated overwrite gate (a pre-existing non-generated file on realRoot is refused, not silently replaced) and is the sole ForceOverwrite=true PlannedFile constructor for the derived path (archtest SCAFFOLD-DERIVED-FORCEOVERWRITE-01).

The depguard scaffold-os-ban rule covers files starting with "scaffold" or "generate_" in tools/codegen/cellgen/; stage_render.go IS also scanned by archtest SCAFFOLD-WRITE-FUNNEL-01 (scaffoldFunnelPred accepts base=="stage_render.go"). Direct os.MkdirTemp / os.RemoveAll / os.ReadFile calls here are intentional and reviewed; write-side ops (MkdirAll/WriteFile/Mkdir/Create/OpenFile) remain banned and would trip the archtest.

Temp-dir cleanup: materializeSkeletonStage uses a named-return + deferred cleanup so that any inner failure (filepath.Rel / WritePlannedFiles) removes the staging dir before returning. appendDerivedCodegenStaged additionally defers RemoveAll for the success path.

Index

Constants

View Source
const ListenerMarker = "// +cell:listener:"

ListenerMarker is the K#05 cell:listener marker literal embedded in scaffolded cell.go output. Templates reference this typed constant via {{.ListenerMarker}} so the marker-string → cell.yaml drift guard (MARKERGEN-DRIFT-VERIFY-01) is fed by a single source of truth.

Hand-typing the marker literal in templates is statically rejected by archtest SCAFFOLD-LISTENER-MARKER-TYPED-CONST-01.

Variables

This section is empty.

Functions

func EnrichGrpcServicesWithProtoInfo

func EnrichGrpcServicesWithProtoInfo(spec *CellGenSpec, root string) error

EnrichGrpcServicesWithProtoInfo populates PbImportPath and PbAlias on each GrpcServiceGenSpec by reading the .proto file at root/spec.ProtoRel via contractgen.ReadProtoServiceInfo. This is a post-build step; BuildCellSpec does not read the filesystem so it cannot derive the import path itself. The .proto is the single source of truth for the method set (#1655); cellgen only needs the import path and alias for the cell_gen.go registration.

It ALSO enforces the proto-referential + #2008 completeness invariants (every public/permission overlay entry ∈ proto method set; every non-public proto RPC carries a permission) via validateGrpcMethodOverlayAgainstProto. Because this runs in the enrich step (which the full `gocell generate cell` pipeline always invokes), a caller that uses BuildCellSpec WITHOUT then calling Enrich skips the completeness check — that path exists only in unit tests, never in production generation.

PbAlias is set to "grpc<index>" (0-indexed) to guarantee uniqueness even when multiple services share the same last path segment.

func EnrichProjectionsWithModulePath

func EnrichProjectionsWithModulePath(spec *CellGenSpec, modulePath string)

EnrichProjectionsWithModulePath populates SpecPackage and SpecAlias on each projection in the spec using the module path derived from go.mod at root. This is a post-build step; BuildCellSpec does not read the filesystem so it cannot derive the import path itself.

SpecAlias is set to "proj<index>" (0-indexed) to guarantee uniqueness even when multiple contracts share the same last path segment.

func EnrichSubscriptionsWithModulePath

func EnrichSubscriptionsWithModulePath(spec *CellGenSpec, modulePath string)

EnrichSubscriptionsWithModulePath populates SubscriptionPackage and SubscriptionAlias on each subscription in the spec using the module path derived from go.mod at root. This is a post-build step; BuildCellSpec does not read the filesystem so it cannot derive the import path itself.

SubscriptionAlias is set to "sub<index>" (0-indexed) to guarantee uniqueness even when multiple contracts share the same last path segment (e.g. multiple "v1" packages).

func PlanCellBundleScaffold

func PlanCellBundleScaffold(realRoot string, spec ScaffoldSpec) ([]pathsafe.PlannedFile, error)

PlanCellBundleScaffold is the K#09 one-shot scaffold planner. It produces a merged []pathsafe.PlannedFile covering:

  • skeleton files (cell.go, cell.yaml, slice artifacts, contract artifacts) with ForceOverwrite=false — conflict detection rejects pre-existing files.
  • when spec.SkipGenerate is false: derived codegen files (cell_gen.go, generated/contracts/.../types_gen.go, iface_gen.go, handler_gen.go) with ForceOverwrite=true — always regenerated without conflict.

Defaults: when neither WithHTTP nor WithEvents is set, WithHTTP applies. WithBoth produces both an HTTP contract and an event contract.

realRoot must be the output of pathsafe.ResolveRoot. The returned plan is written by the caller via a single pathsafe.WritePlannedFiles call, ensuring all-or-nothing atomicity across skeleton + derived files.

Mirrors kernel/assembly.Generator.PlanAssemblyScaffold + appendGeneratedFiles.

func ScaffoldCell

func ScaffoldCell(root, targetDir string, spec ScaffoldSpec) error

ScaffoldCell renders a new cell skeleton at root/<targetDir> with stub markers, cell.yaml, and the K#05 marker conventions in place. Returns an error if any output file already exists (caller must remove first).

Generated files:

  • <root>/<targetDir>/cell.go — struct + stub markers + initInternal hook
  • <root>/<targetDir>/cell.yaml — metadata with goStructName set

All filesystem writes go through pathsafe.WritePlannedFiles (SCAFFOLD-WRITE-FUNNEL-01).

Types

type CellArtifact

type CellArtifact struct {
	// Kind is "cell-gen" or "slice-gen".
	Kind string
	// RelPath is the project-relative path the file would be written to,
	// e.g. "examples/todoorder/cells/ordercell/cell_gen.go".
	RelPath string
	// Content is the rendered, formatted, goimports-processed bytes.
	Content []byte
}

CellArtifact is a (RelPath, Kind, Content) triple describing one rendered cellgen output for a single cell. Returned by RenderCellArtifacts so other tools (notably tools/generatedverify) can build a project-derived expected manifest without going through the filesystem-mutating Generate path.

func RenderCellArtifacts

func RenderCellArtifacts(root string, project *metadata.ProjectMeta, cellID, modulePath string) ([]CellArtifact, error)

RenderCellArtifacts renders the cellgen output for a single cell to memory without touching disk. Returns one CellArtifact per produced file (one cell_gen.go plus one slice_gen.go per slice with subscribes). Cells without GoStructName return (nil, nil) — same opt-in semantics as Generate.

modulePath is the consuming repo's module path, threaded to the formatter and subscription import enrichment (#1083). It is required and supplied by the caller — callers resolve it from the real repo's go.mod (the render root may be a staging dir without a go.mod, e.g. scaffold staging in stage_render.go).

Implementation note: render must be ordered cell→slices in a single pass because the cell template's imports are inferred from per-slice subscribes; extracting per-slice render into a helper duplicates the import accumulator.

type CellFieldIndex

type CellFieldIndex struct {
	// contains filtered or unexported fields
}

CellFieldIndex indexes the pointer fields of a cell.go cell struct so that a subscribe CU resolves to a concrete, typed cell-struct field before cellgen renders the `c.<field>.<handler>` expression. It is the typed target the reviewer's "resolve to a determinate typed target before rendering" direction requires: a field reference never reaches code generation as a bare name.

Two complementary lookups, both derived from the SAME single cell struct:

  • byPkg: slice package short name → field name. Drives convention resolution (slice package short name == sliceID). A package that appears on more than one field maps to ambiguousField ("").
  • byField: field name → slice package short name. Validates an explicit slice.yaml `field:` actually points at the SUBSCRIBING slice's own package (byField[field] == sliceID), so a misdirected `field:` fails generation instead of silently binding the subscription to a different slice whose type happens to expose a same-named method.

func IndexCellStructFields

func IndexCellStructFields(cellGoPath, cellStructName string) (*CellFieldIndex, error)

IndexCellStructFields parses the Go source at cellGoPath and indexes the *pkg.Type pointer fields of the single struct named cellStructName (the cell struct named by cell.yaml goStructName).

Only that one struct is scanned: helper / option / config structs declared in the same cell.go cannot pollute the index or manufacture false ambiguity (e.g. an options struct that also holds a *orderprojection.Foo field must not shadow the cell struct's own field, nor flip a package to ambiguous).

Only *pkg.Type fields (StarExpr → SelectorExpr → Ident) are indexed. Non-pointer fields, embedded (anonymous) fields, and fields whose type is not a qualified selector (plain same-package types) are ignored. When cellStructName is not declared in the file the returned index is empty (a subscribing slice then fails with a descriptive "no cell.go struct field" error from resolveSliceField).

Example: for the cell struct `type AccessCore struct { projectionSvc *orderprojection.Service }`, byPkg["orderprojection"] == "projectionSvc" and byField["projectionSvc"] == "orderprojection".

type CellGenSpec

type CellGenSpec struct {
	// Package is the Go package name for cell_gen.go.
	Package string
	// StructName is the receiver type (CellMeta.GoStructName).
	StructName string
	// CellID is CellMeta.ID — used for fmt.Errorf wrapping in Init.
	CellID string
	// ConsumerGroupDefault is the cell ID, used when a SubscriptionGenSpec
	// omits its ConsumerGroup.
	ConsumerGroupDefault string
	// SourceFile is the project-relative path of the cell.yaml that drove
	// generation (e.g. "examples/todoorder/cells/ordercell/cell.yaml").
	// Rendered into the file header as "// Source: <SourceFile>" so that
	// readers of the generated file can locate the authoritative YAML.
	SourceFile string
	// RenderedMetaLiteral is the pre-rendered Go source literal for the cell's
	// metadata, of the form "&metadata.CellMeta{...}". BuildCellSpec calls
	// renderCellMetaLiteral(cell) at spec build time and assigns the result;
	// cell.tmpl emits the string verbatim into
	// `var cellMeta = {{ .RenderedMetaLiteral }}`.
	//
	// CELLGEN-LITERAL-FUNNEL-02 Hard source (highest type-system grade):
	// cell.tmpl cannot reach *metadata.CellMeta because CellGenSpec does not
	// expose it. Hand-enumeration of CellMeta fields in the template is
	// structurally unreachable — there is no data source to access. Any
	// attempt to bypass the reflect-driven renderer must change the type of
	// this field, which is a public API change and therefore review-visible.
	RenderedMetaLiteral string
	// RouteGroups holds the listener-aggregated route mounts. Each entry
	// emits one reg.RouteGroup() call.
	RouteGroups []RouteGroupGenSpec
	// Subscriptions holds the per-slice event subscriptions. Each entry
	// emits one reg.Subscribe() call (and one specEvent... var declaration).
	Subscriptions []SubscriptionGenSpec
	// WebhookReceivers holds the per-slice inbound webhook registrations.
	// Each entry emits one reg.RegisterWebhookReceiver() call.
	WebhookReceivers []WebhookReceiverGenSpec
	// WebhookDispatches holds the per-slice outbound webhook registrations.
	// Each entry emits one reg.RegisterWebhookDispatch() call.
	WebhookDispatches []WebhookDispatchGenSpec
	// Projections holds the per-slice CQRS projection registrations derived from
	// subscribe CUs that carry a non-empty projection: field. Each entry emits
	// one reg.RegisterProjection() call.
	Projections []ProjectionGenSpec
	// GrpcServices holds the per-slice gRPC serve registrations derived from
	// contractUsages[role=serve] with kind=grpc. Each entry emits one
	// reg.GRPCService() call.
	GrpcServices []GrpcServiceGenSpec
	// HTTPMethodPermissions holds the cell-level (contractID → ABAC action) pairs
	// derived from each served HTTP contract's endpoints.http.permission overlay
	// (#2205), sorted by contract id for deterministic golden output. When non-empty,
	// cell.tmpl renders a package-level resolver var
	// `<cell>HTTPResolver = auth.NewStaticMethodPolicyResolver(map[string]string{...})`
	// (the HTTP transport's authz.MethodPolicyResolver, sibling of the gRPC
	// registrar) that cell_init.go injects into the contract-derived slice handlers.
	// Empty → no contract-derived HTTP gates in this cell; the resolver var and its
	// runtime/auth import are omitted. MethodPermission.FullMethod holds the contract
	// id here (not a gRPC method name); the field is reused to avoid a near-duplicate
	// string→string pair type.
	HTTPMethodPermissions []MethodPermission
}

CellGenSpec is the rendering input for cell.tmpl. It is the projection of CellMeta + child slices that the template needs to emit cell_gen.go.

Fields are deterministically ordered (declaration order matters for diff stability — sort upstream before populating slices).

func BuildCellSpec

func BuildCellSpec(
	p *metadata.ProjectMeta,
	cellID string,
	bundle markergen.WireBundle,
	fieldIndex *CellFieldIndex,
) (*CellGenSpec, error)

BuildCellSpec projects (cell.yaml + markergen.WireBundle + fieldIndex) into the CellGenSpec consumed by cell.tmpl. It is the single bridge between parsed metadata and the renderer.

bundle supplies listener / route wire declarations derived from cell.go marker comments (markergen.Merge output). An empty bundle produces a spec with no RouteGroups.

fieldIndex indexes the cell struct's pointer fields (by slice package short name and by field name). It is derived by IndexCellStructFields(cellGoPath, goStructName). Pass nil when no subscriptions are expected; a nil index with subscribe CUs in slices will produce an error.

Subscriptions are derived from slice.yaml contractUsages[role=subscribe], not from bundle.Subscribes (subscribe single-source flip K05 W3).

Errors:

  • cell id not found in project
  • cell.GoStructName missing (codegen requires explicit Go type binding)
  • bundle listener ref does not match expected pattern
  • bundle route references a listener not declared in bundle.Listeners
  • subscribe CU handler field empty
  • subscribe CU references a contract not declared in project
  • fieldIndex missing entry for subscribing slice

type GrpcServiceGenSpec

type GrpcServiceGenSpec struct {
	// ContractID is the gRPC contract id, e.g. "grpc.device.command.v1".
	ContractID string
	// SliceID identifies the slice owning the server implementation — primary
	// sort key (mirrors SubscriptionGenSpec).
	SliceID string
	// HandlerField is the cell struct field name holding the gRPC server
	// implementation, e.g. "commandServer".
	HandlerField string
	// RegisterFunc is the protoc-gen-go-grpc generated registration function,
	// e.g. "RegisterDeviceCommandServiceServer". Derived from the last
	// dot-segment of the proto service FQN + "Server".
	RegisterFunc string
	// ListenerConst is the Go constant reference for the gRPC listener;
	// always "cell.PrimaryListener" for grpc-serve (rendered verbatim).
	ListenerConst string
	// ProtoRel is the contracts-relative path of the .proto file,
	// e.g. "contracts/grpc/device/command/v1/device_command.proto".
	// Used by EnrichGrpcServicesWithProtoInfo to resolve the import path.
	ProtoRel string
	// Service is the proto fully-qualified service name,
	// e.g. "device.command.v1.DeviceCommandService".
	// Retained for proto-info resolution (EnrichGrpcServicesWithProtoInfo passes
	// it to contractgen.ReadProtoServiceInfo) and is NOT rendered directly into
	// cell_gen.go; only RegisterFunc/PbAlias/HandlerField/ContractID/ListenerConst
	// appear in the generated output.
	Service string
	// PbImportPath is the Go import path of the generated proto package.
	// Populated by EnrichGrpcServicesWithProtoInfo (post-build, FS-derived).
	PbImportPath string
	// PbAlias is the import alias for PbImportPath in cell_gen.go,
	// e.g. "grpc0", "grpc1". Set by EnrichGrpcServicesWithProtoInfo.
	PbAlias string
	// PublicMethods lists the FULL method names (/{Service}/{Method}) marked
	// JWT-exempt by the contract's endpoints.grpc.methods[] overlay (the
	// public:true entries, #1675). Composed in buildGrpcServiceSpecFromCU from the
	// overlay + Service FQN; rendered into the generated GRPCServiceSpec literal so
	// the runtime registrar aggregates them into the auth interceptor's bypass set.
	// Empty → no public methods (the fail-closed default). Referential integrity
	// (each name ∈ proto method set) is enforced by the contractgen pre-pass.
	PublicMethods []string
	// MethodPermissions lists the (FULL method name → ABAC action) pairs derived
	// from the contract's endpoints.grpc.methods[] permission entries (#2008),
	// sorted by full method name for deterministic golden output. Rendered into the
	// generated GRPCServiceSpec literal as a map[string]string the runtime registrar
	// resolves to sealed authz.Permissions for the PDP gate. Empty → no permission
	// gates; the completeness pre-pass rejects a non-public proto method with no
	// permission, so empty means the service is all-public or has no authed RPCs.
	MethodPermissions []MethodPermission
	// MethodResources lists the (FULL method name → request message field name) pairs
	// derived from the contract's endpoints.grpc.methods[] resource entries (#2207),
	// sorted by full method name for deterministic golden output. Rendered into the
	// generated GRPCServiceSpec literal as a map[string]string. Empty → no owner-scoped
	// per-message resource extraction; all methods use fullMethod as PDP resource (coarse).
	MethodResources []MethodResource
	// PasswordResetExemptMethods lists the FULL method names (/{Service}/{Method})
	// marked exempt from the password-reset gate by the contract's
	// endpoints.grpc.methods[] overlay (the passwordResetExempt:true entries, #1382).
	// Composed in buildGrpcServiceSpecFromCU from the overlay + Service FQN;
	// rendered into the generated GRPCServiceSpec literal so the runtime registrar
	// aggregates them into the auth interceptor's exempt set.
	// Empty → no exempt methods (the fail-closed default). Referential integrity
	// (each name ∈ proto method set) is enforced by the contractgen pre-pass.
	PasswordResetExemptMethods []string
}

GrpcServiceGenSpec describes one reg.GRPCService() call derived from a contractUsage[role=serve] on a grpc contract.

type HealthzGenSpec

type HealthzGenSpec struct {
	// Package is the Go package name for healthz_gen.go (= CellMeta.Dir).
	Package string
	// CellID is the cell id — used to construct the ProbeRepoReady constant
	// value ("<cellid>_repo_ready") and the godoc comment.
	CellID string
	// SourceFile is the project-relative path of the cell.yaml that drove
	// generation. Rendered into the file header as "// Source: <SourceFile>".
	SourceFile string
}

HealthzGenSpec is the rendering input for healthz_gen.tmpl. It projects the cell id and package needed to emit healthz_gen.go — the typed RegisterReadiness helper that is the sole sanctioned way for a cell to register its repo readiness probe (locked by PROBENAME-SEALED-FUNNEL-01).

The file is emitted unconditionally for every cell that opts into codegen (GoStructName present). Cells that do not have a primary repository simply never call RegisterReadiness; exported helpers do not trigger an unused-symbol compile error.

type MethodPermission

type MethodPermission struct {
	// FullMethod is the /{Service}/{Method} name, e.g.
	// "/device.command.v1.DeviceCommandService/IssueCommand".
	FullMethod string
	// Permission is the ABAC action string, e.g. "device:command".
	Permission string
}

MethodPermission pairs a full gRPC method name with its required ABAC action string (#2008). The slice form (vs a map) keeps the rendered golden deterministic — buildGrpcServiceSpecFromCU sorts by FullMethod.

type MethodResource

type MethodResource struct {
	// FullMethod is the /{Service}/{Method} name, e.g.
	// "/device.command.v1.DeviceCommandService/WatchCommands".
	FullMethod string
	// Field is the proto request message field name (snake_case), e.g. "device_id".
	// The interceptor extracts it via protoreflect and canonicalizes the value.
	Field string
}

MethodResource pairs a full gRPC method name with the request message field name whose value is forwarded as the PDP resource for per-message ownership authz (#2207). The slice form keeps the rendered golden deterministic.

type Options

type Options struct {
	// DryRun emits ActionWouldWrite without filesystem mutation.
	DryRun bool
	// Verify diffs the rendered content against disk and reports drift.
	// Mutually exclusive with DryRun at the CLI layer; combining them here
	// is harmless (Verify dominates — no write either way).
	Verify bool
	// OnlyCell, when non-empty, restricts generation to a single cell id.
	// Empty = generate for every cell in project.
	OnlyCell string
	// ModulePath is the consuming repo's Go module path (from its go.mod),
	// threaded to the formatter so generated files group module-local imports
	// the way the target repo's golangci-lint gate expects (#1083). Required:
	// Generate rejects an empty ModulePath. The CLI resolves it via
	// resolveModule (flag-or-go.mod); RenderCellArtifacts resolves it from root.
	ModulePath string
}

Options controls a Generate run.

type ProjectionGenSpec

type ProjectionGenSpec struct {
	ContractID   string // event contract id (input stream); Spec.Kind=="event"
	SliceID      string // primary sort key (mirrors SubscriptionGenSpec)
	ProjectionID string // snake_case probe-name; half of checkpoint key
	ApplyExpr    string // dotted apply ref, e.g. "c.projSvc.HandleOrderCreated"
	OnResetExpr  string // dotted onReset ref or "" (renders nil)
	// Source selects the projection input stream. "" or "outbox" → outbox path
	// (per-event-contract NewProjectionRequest with a SpecPackage/SpecAlias import);
	// "saga-journal" → saga path (cell.NewSagaJournalProjectionRequest, no event Spec,
	// no OnReset, SpecPackage/SpecAlias stay empty).
	Source string
	// Populated by EnrichProjectionsWithModulePath (post-build, FS-derived);
	// stays empty for saga-journal sources (no per-contract import):
	SpecPackage string // import path of the generated event contract package
	SpecAlias   string // "proj0","proj1",... unique import alias
}

ProjectionGenSpec describes one reg.RegisterProjection() call derived from a subscribe CU carrying a projection: field.

func (ProjectionGenSpec) IsSagaJournal

func (s ProjectionGenSpec) IsSagaJournal() bool

IsSagaJournal reports whether this projection uses the saga-journal source. cell.tmpl branches on it (import guard + wiring constructor) so the template carries no raw "saga-journal" literal — Source stays the single source.

type Result

type Result struct {
	// Generated lists files that were written, would-have-been-written
	// (DryRun), or remain unchanged (Unchanged).
	Generated []string
	// Drifted lists files whose disk content differs from the freshly
	// rendered content (Verify mode).
	Drifted []string
}

Result aggregates per-call outcomes for CLI reporting.

func Generate

func Generate(root string, project *metadata.ProjectMeta, opts Options) (Result, error)

Generate runs the cellgen pipeline against the parsed project.

  • Selects cells: OnlyCell or all in project.Cells (deterministically ordered).
  • For each cell: BuildCellSpec → Render(cell.tmpl) → Write cell_gen.go.
  • For each slice with Subscribes: BuildSliceSpec → Render(slice.tmpl) → Write slice_gen.go. Slices without subscribes do not produce output.

Returns a Result describing per-file actions. The error return is non-nil only for hard failures (spec invalid, template execution, write IO); drift in Verify mode populates Result.Drifted without an error.

func (Result) DriftedFiles

func (r Result) DriftedFiles() []string

DriftedFiles satisfies the cmd/gocell/app.CodegenResult interface.

func (Result) GeneratedFiles

func (r Result) GeneratedFiles() []string

GeneratedFiles satisfies the cmd/gocell/app.CodegenResult interface.

type RouteGroupGenSpec

type RouteGroupGenSpec struct {
	// ListenerConst is the Go constant reference for the listener
	// (e.g. "cell.PrimaryListener"). Rendered verbatim.
	ListenerConst string
	// Prefix is the URL prefix mounted on the listener (e.g. "/api/v1").
	Prefix string
	// SubRoutes groups handler mounts by subPath. A nil/empty SubPath
	// means the handler attaches directly to the prefix.
	SubRoutes []RouteSubGroup
}

RouteGroupGenSpec describes one reg.RouteGroup() call.

type RouteSliceMount

type RouteSliceMount struct {
	HandlerField string
	// Method is the registration method on the handler. Zero value is unsafe —
	// populate via BuildCellSpec which substitutes "RegisterRoutes" when the
	// YAML omits it.
	Method string
}

RouteSliceMount is a single slice-handler invocation inside a sub-route closure: c.<HandlerField>.<Method>(s).

type RouteSubGroup

type RouteSubGroup struct {
	// SubPath is the path relative to the listener prefix. Empty SubPath
	// indicates direct attachment (no mux.Route wrapper).
	SubPath string
	// Mounts lists the slice handler invocations inside the closure,
	// preserving declaration order across slices for diff stability.
	Mounts []RouteSliceMount
}

RouteSubGroup is one mux.Route(subPath, ...) block aggregating multiple slice handlers under a shared sub-path.

type ScaffoldSpec

type ScaffoldSpec struct {
	// CellID is the cell identifier (e.g. "foocell"). Typed so the
	// (^[a-z][a-z0-9]+$) constraint is established at construction time via
	// scaffoldid.Parse — callers cannot supply an unvalidated raw string
	// (SCAFFOLD-INPUT-CONTRACT-TYPED-ID-01).
	CellID scaffoldid.ScaffoldID
	// StructName is the Go struct name (e.g. "FooCell").
	StructName string
	// Package is the Go package name (e.g. "foocell").
	Package string
	// ModulePath is the Go module path (e.g. "github.com/ghbvf/gocell").
	ModulePath string
	// OwnerTeam is the team responsible for this cell (e.g. "platform").
	// Required. Written as-is to cell.yaml owner.team.
	OwnerTeam string
	// OwnerRole is the ownership role for this cell (e.g. "cell-owner").
	// Required. Written as-is to cell.yaml owner.role.
	OwnerRole string
	// Type is the cell type. Must be one of validCellTypes.
	// Defaults to "core" when empty.
	Type string
	// ConsistencyLevel is the cell consistency level. Must be one of validConsistencyLevels.
	// Defaults to "L1" when empty.
	ConsistencyLevel string
	// SkipGenerate, when true, skips the appended cellgen/contractgen derived
	// artifacts from PlanCellBundleScaffold. The resulting plan contains only
	// skeleton files. Mirrors assembly.AssemblyScaffoldSpec.SkipGenerate semantics.
	SkipGenerate bool
	// WithHTTP, WithEvents, WithBoth control K#09 ScaffoldCellBundle's contract
	// variant. WithHTTP produces an HTTP request/response contract (default
	// when none of the three flags are set). WithEvents produces an event
	// payload/headers contract. WithBoth produces both.
	WithHTTP   bool
	WithEvents bool
	WithBoth   bool
}

ScaffoldSpec holds the inputs required to render a new cell skeleton.

type SliceGenSpec

type SliceGenSpec struct {
	// Package is the Go package name for slice_gen.go.
	Package string
	// CellID identifies the parent cell (used in interface comment).
	CellID string
	// SliceID identifies this slice (used in interface comment).
	SliceID string
	// SourceFile is the project-relative path of the slice.yaml that drove
	// generation (e.g. "examples/todoorder/cells/ordercell/slices/ordercreate/slice.yaml").
	// Rendered into the file header as "// Source: <SourceFile>".
	SourceFile string
	// Handlers lists the handler methods the slice's service must provide.
	// Order is deterministic to keep generated diff stable.
	Handlers []SliceHandlerSpec
	// RenderedMetaLiteral is the pre-rendered Go source literal for the
	// slice's metadata.SliceMeta value (the typed projection of slice.yaml).
	// BuildSliceSpec invokes renderSliceMetaLiteral(s) at spec build time and
	// assigns the result; slice.tmpl emits `var sliceMeta = {{ .RenderedMetaLiteral }}`.
	RenderedMetaLiteral string
}

SliceGenSpec is the rendering input for slice.tmpl. It declares the canonical Service interface a slice must implement so that the cell can call its handler methods through a typed reference, and projects the parsed slice.yaml into a typed `sliceMeta` literal that the cell composition root consumes via cell.MustNewBaseSliceFromMeta.

func BuildSliceSpec

func BuildSliceSpec(p *metadata.ProjectMeta, cellID, sliceID string) (*SliceGenSpec, error)

BuildSliceSpec returns the rendering input for slice.tmpl. Every slice in the project produces a slice_gen.go with a typed `sliceMeta` literal so that cell composition roots can build BaseSlice through the funnel `cell.MustNewBaseSliceFromMeta(<slicePkg>.SliceMetadata())`. Slices that also declare event subscriptions via contractUsages[role=subscribe] get the typed eventHandlerService interface rendered alongside the metadata literal.

Handlers are derived from the slice's ContractUsages (not from a WireBundle) as part of the subscribe single-source flip (K05 W3).

type SliceHandlerSpec

type SliceHandlerSpec struct {
	// MethodName is the Go method name, e.g. "HandleOrderCreated".
	MethodName string
	// ContractID is the contract that triggers the handler — included as a
	// godoc reference on the generated interface method.
	ContractID string
}

SliceHandlerSpec describes one method on the slice Service interface generated in slice_gen.go.

type SubscriptionGenSpec

type SubscriptionGenSpec struct {
	// ContractID is the full event contract id, e.g. "event.config.entry-upserted.v1".
	ContractID string
	// SliceID identifies the slice owning the handler — used for
	// cell.WithSubscriptionSliceID().
	SliceID string
	// HandlerExpr is the dotted handler reference e.g. "c.subscribeSvc.HandleEntryUpserted".
	HandlerExpr string
	// ConsumerGroup is the broker consumer-group identifier. When empty
	// the renderer falls back to CellGenSpec.ConsumerGroupDefault.
	ConsumerGroup string
	// SubscriptionPackage is the Go import path for the generated contract package
	// that provides NewSubscription, e.g.
	// "github.com/ghbvf/gocell/generated/contracts/event/order-created/v1".
	// Populated by BuildCellSpec from the contract id via contractIDToImportPath.
	SubscriptionPackage string
	// SubscriptionAlias is the import alias used in cell_gen.go for SubscriptionPackage
	// (e.g. "sub0", "sub1") to avoid package name collisions between multiple v1 packages.
	SubscriptionAlias string
}

SubscriptionGenSpec describes one reg.Subscribe() call.

type WebhookDispatchGenSpec

type WebhookDispatchGenSpec struct {
	// ContractID is the webhook contract id, e.g. "webhook.shopify.orders.v1".
	ContractID string
	// SliceID identifies the slice owning the selector — the primary sort key so
	// output ordering is deterministic even when one contract is wired by more
	// than one slice (mirrors SubscriptionGenSpec).
	SliceID string
	// SourceID is the signing-secret source (slice.yaml contractUsages.sourceID).
	SourceID string
	// SelectorExpr is the dotted selector reference, e.g. "c.shopifySvc.ShopifyTarget".
	SelectorExpr string
}

WebhookDispatchGenSpec describes one reg.RegisterWebhookDispatch() call.

type WebhookReceiverGenSpec

type WebhookReceiverGenSpec struct {
	// ContractID is the webhook contract id, e.g. "webhook.stripe.payment-events.v1".
	ContractID string
	// SliceID identifies the slice owning the handler — the primary sort key so
	// output ordering is deterministic even when one contract is wired by more
	// than one slice (mirrors SubscriptionGenSpec).
	SliceID string
	// SourceID is the secret-isolation key (slice.yaml contractUsages.sourceID).
	SourceID string
	// HandlerExpr is the dotted handler reference, e.g. "c.stripeSvc.HandleStripeEvent".
	HandlerExpr string

	// Runtime configuration baked from contract.yaml at code-generation time.
	// PathPattern is the HTTP path the receiver runtime mounts
	// (contract.yaml endpoints.inbound.pathPattern).
	PathPattern string
	// DeliveryIDHeader is the HTTP header name carrying the per-delivery
	// identifier (contract.yaml signature.deliveryIDHeader).
	DeliveryIDHeader string
	// TimestampHeader is the HTTP header name carrying the unix-seconds
	// timestamp (contract.yaml signature.timestampHeader).
	TimestampHeader string
	// SignatureHeader is the HTTP header name carrying the HMAC signature tokens
	// (contract.yaml signature.signatureHeader).
	SignatureHeader string
	// ToleranceSeconds is the bidirectional timestamp window in seconds
	// (contract.yaml signature.toleranceSeconds). Must be > 0.
	ToleranceSeconds int64
	// MaxBodyBytes is the maximum accepted request body size in bytes
	// (contract.yaml payload.maxBodyBytes). Must be > 0.
	MaxBodyBytes int64
}

WebhookReceiverGenSpec describes one reg.RegisterWebhookReceiver() call.

Jump to

Keyboard shortcuts

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