reconcile

package
v0.20.0 Latest Latest
Warning

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

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

Documentation

Overview

Package reconcile is the pure functional core for the server's gate/grant and execution-lifecycle state. It performs no I/O: Step takes an observed World plus a Signal and returns the new ChangeSet plus the minimal set of Actions the imperative shell must execute. See docs/superpowers/specs/2026-06-15-reconciler-core-design.md.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MarshalEvent added in v0.17.0

func MarshalEvent(e Event) (string, []byte, error)

MarshalEvent serializes a domain Event to a neutral (typeTag, JSON) pair. The tag is the variant's Go type name; the data is its JSON. Neutral types only — no store dependency. Keep this switch and UnmarshalEvent in sync with the Event variants in event.go (the round-trip-every-variant test enforces it).

func MarshalSnapshot added in v0.17.0

func MarshalSnapshot(cs ChangeSet) ([]byte, error)

MarshalSnapshot serializes a folded ChangeSet (the GateState sum type is encoded with a discriminator). Neutral []byte — no store dependency.

func Requester

func Requester(g GateState) string

Requester returns the leased requester identity for the gate ("" if none).

Types

type Action

type Action interface {
	// contains filtered or unexported methods
}

Action is an effect the pure core wants performed but cannot do itself.

func React added in v0.17.0

func React(state ChangeSet, evs []Event) []Action

React projects the effects (Actions) the shell must perform from the domain facts. Presentation (RenderCheckRun/PublishSSE) is derived here, never stored as an Event. Action ordering must match step_table_test.go exactly.

type ApplySucceeded

type ApplySucceeded struct{}

type BlockReason

type BlockReason string
const (
	ReasonDenied       BlockReason = "denied"
	ReasonExpired      BlockReason = "expired"
	ReasonRevoked      BlockReason = "revoked"
	ReasonSlotForeign  BlockReason = "slot_foreign_open" // another open PR holds the slot (⑥)
	ReasonSlotSelf     BlockReason = "slot_self"         // same PR, another env, holds the slot (⑥)
	ReasonBackendError BlockReason = "backend_error"
)

type Blocked

type Blocked struct {
	Targets []Target
	Lease   Lease
	By      Blocker
}

type Blocker

type Blocker struct {
	Reason BlockReason
	ByPR   int    // slot blocker's PR (0 if N/A)
	ByEnv  string // slot blocker's environment
}

Blocker explains why a gate is Blocked.

type ChangeSet

type ChangeSet struct {
	PR          int
	Environment string
	Exec        Execution
	Gate        GateState
}

ChangeSet is the reconciliation unit: one PR's work in one environment.

func Evolve added in v0.17.0

func Evolve(cs ChangeSet, e Event) ChangeSet

Evolve applies a single domain Event to a ChangeSet, returning the new state. It is total (never panics on any state/event combination), pure (no I/O), and deterministic. It is the fold half of the Decider pattern: Decide emits Events, Evolve reduces them into state.

func UnmarshalSnapshot added in v0.17.0

func UnmarshalSnapshot(b []byte) (ChangeSet, error)

UnmarshalSnapshot reverses MarshalSnapshot.

type ClaimReleased added in v0.17.0

type ClaimReleased struct {
	PR          int
	Environment string
}

type Classified added in v0.17.0

type Classified struct{ Gates []events.GateTarget }

Classified establishes/replaces the gate target set. Evolve carries forward still-live prior grants (gap ② anti-clobber); Decide has already resolved the effective set (plan-authoritative vs apply-recovery union).

type Clean

type Clean struct{} // classified, zero gates → apply passes

type Collision

type Collision struct {
	ByPR          int
	ByEnv         string
	BySelf        bool // ByPR == this changeset's PR (different env)
	ByPRAbandoned bool // shell looked up the blocker PR's GitHub state (closed && !merged)
}

Collision describes a slot blocker the shell already resolved against GitHub.

type Event added in v0.17.0

type Event interface {
	// contains filtered or unexported methods
}

Event is a past-tense domain fact produced by Decide and folded by Evolve. Events are domain facts ONLY — presentation (check run / SSE) is never an Event; React projects that from the event stream. See the Phase 3 design.

func Decide added in v0.17.0

func Decide(state ChangeSet, s Signal) []Event

Decide computes the past-tense domain facts that result from applying Signal s to the prior state. All business logic lives here; Evolve only folds.

func UnmarshalEvent added in v0.17.0

func UnmarshalEvent(tag string, data []byte) (Event, error)

UnmarshalEvent reverses MarshalEvent.

type Execution

type Execution struct {
	ID     string
	Repo   string
	SHA    string
	LogURL string
	Phase  events.Phase
	Stacks []Stack
}

Execution is the plan/apply run for the ChangeSet (edge-triggered facts).

type ExecutionFailed added in v0.17.0

type ExecutionFailed struct{}

type ExecutionStarted added in v0.17.0

type ExecutionStarted struct{ Exec Execution }

type GateBlocked added in v0.17.0

type GateBlocked struct {
	Reason BlockReason
	ByPR   int
	ByEnv  string
}

type GatePassed added in v0.17.0

type GatePassed struct{}

GatePassed and GateReleased both fold the gate to Clean. They are distinct facts so React can present them differently: GatePassed (plan-clean / nothing to gate) renders success; GateReleased (post-apply cleanup) renders nothing.

type GateReleased added in v0.17.0

type GateReleased struct{}

type GateSatisfied added in v0.17.0

type GateSatisfied struct{}

type GateState

type GateState interface {
	// contains filtered or unexported methods
}

GateState is a sum type: a gate is EXACTLY one of these.

type GateTargetRequested added in v0.17.0

type GateTargetRequested struct{ Class, Target, Requester string } // Requester pins the lease (step.go:140)

type GateTick

type GateTick struct{ Grants []ObservedGrant }

GateTick is the periodic backstop re-observation; Grants is a full re-list of the changeset's targets. Processed identically to GrantsObserved.

type GrantCleared added in v0.17.0

type GrantCleared struct{ Class, Target string }

type GrantObserved added in v0.17.0

type GrantObserved struct {
	Class, Target, Name string
	State               approval.GrantState
	Requester           string
}

type GrantsObserved

type GrantsObserved struct{ Grants []ObservedGrant }

GrantsObserved carries grant observations for THIS changeset: either the results of RequestGrant actions (fixpoint feedback) or a re-list. Grants not mentioned are left unchanged.

type Lease

type Lease struct{ Requester string }

Lease is the pooled requester identity leased once per ChangeSet. Empty Requester means undecided.

type NotClassified

type NotClassified struct{} // never planned → apply fails closed

type ObservedGrant

type ObservedGrant struct {
	Class     string
	Target    string
	Name      string              // backend-assigned id ("" if none)
	State     approval.GrantState // "" == no grant present for this changeset
	Requester string              // leased identity ("" if N/A)
	Collision *Collision          // set when a RequestGrant hit a SlotCollisionError
}

ObservedGrant is one grant fact the shell gathered for a (class,target).

type PRClosed

type PRClosed struct{}

type PRClosedRecorded added in v0.17.0

type PRClosedRecorded struct{}

PRClosedRecorded marks a PR-closure teardown so React renders SSE-only (no check run), distinct from an externally-observed revocation. Named *Recorded to avoid colliding with the PRClosed Signal.

type Pending

type Pending struct {
	Targets []Target
	Lease   Lease
}

type PhaseChanged added in v0.17.0

type PhaseChanged struct{ Phase events.Phase }

type PostCommitStatus

type PostCommitStatus struct {
	State       string // "success" | "failure" | "pending"
	Description string
}

PostCommitStatus posts the commit status. Pure output; no result.

type PublishSSE

type PublishSSE struct{}

PublishSSE notifies the live-page hub that state changed. Pure output.

type ReleaseClaim added in v0.16.2

type ReleaseClaim struct {
	PR          int
	Environment string
}

ReleaseClaim releases the merge-lock stack claim a PR holds in an environment. Emitted post-apply (the apply is done, so the claim it held is no longer needed). The shell deletes the claims and re-evaluates the env's held apply-lock checks (cross-PR I/O). Idempotent.

type RenderCheckRun

type RenderCheckRun struct {
	Terminal   bool
	Conclusion string // "success" | "action_required" | "failure" | "" (in-progress)
}

RenderCheckRun re-renders the GitHub check run from current state. Pure output; no result.

type RequestGrant

type RequestGrant struct {
	Class     string
	Target    string
	Requester string
}

RequestGrant asks the backend to ensure an open grant. It YIELDS a result (grant name + leased requester, or a Collision) the shell feeds back as a GrantsObserved signal. Requester pins the lease; "" lets the backend lease.

type RevokeGrant

type RevokeGrant struct {
	Class       string
	Target      string
	PR          int
	Environment string
}

RevokeGrant revokes the open grant for (class,target,PR,environment). Idempotent; produces no result. PR/Environment default to the changeset's when zero/empty but are set explicitly when revoking a foreign slot blocker.

type RunnerFinalize

type RunnerFinalize struct {
	Failed         bool
	ReportMarkdown string
	Projects       map[string]string            // stack path → grouping/target key
	Categories     map[string][]events.Category // stack path → matched categories
	Moving         []string                     // stack paths adopting via cross-state move
	Gates          []events.GateTarget          // (class,target) pairs needing approval
	// ApplyContext marks a finalize from the post-merge apply (apply/<env>) rather
	// than the plan gate. An apply finalize is a RECOVERY signal, not an authority:
	// it may add/refresh gate targets but must never weaken a gate the plan already
	// established (issue #103) — so decideFinalize unions the prior targets and never
	// prunes when this is set. A plan finalize (false) stays authoritative.
	ApplyContext bool
}

type RunnerInit

type RunnerInit struct{ Exec Execution }

type RunnerPhase

type RunnerPhase struct{ Phase events.Phase }

type RunnerUpdate

type RunnerUpdate struct {
	Stack  string
	Status events.Status
	Detail string
}

type Satisfied

type Satisfied struct {
	Targets []Target
	Lease   Lease
}

type Signal

type Signal interface {
	// contains filtered or unexported methods
}

Signal is the union of everything that can drive a ChangeSet.

type Stack

type Stack struct {
	Path       string
	Project    string
	RunStatus  events.Status // pending|running|planned|failed|moving (never gated/safe)
	Detail     string
	Categories []events.Category
}

Stack is one node. RunStatus holds ONLY the runner-told statuses; the gated/safe overlay is derived from the ChangeSet's GateState (see project.go).

type StackStatusChanged added in v0.17.0

type StackStatusChanged struct {
	Stack  string
	Status events.Status
	Detail string
}

type StacksClassified added in v0.17.0

type StacksClassified struct {
	Projects   map[string]string
	Categories map[string][]events.Category
}

type Target

type Target struct {
	Class     string
	Target    string
	GrantName string              // backend-assigned id; "" until created
	Grant     approval.GrantState // observed grant lifecycle; "" == no grant/absent
}

Target is one (class,target) gate and its observed grant.

type TargetRevoked added in v0.17.0

type TargetRevoked struct {
	Class, Target string
	PR            int
	Env           string
}

type World

type World struct {
	Prior   ChangeSet
	Version int
}

World is the scoped, immutable snapshot the shell hands to Step/Decide. Prior is the current persisted state for (PR, Environment); Version is the event stream's current version (0 for an empty stream), used for optimistic- concurrency append. Observations ride on the Signal. The core performs no I/O.

Jump to

Keyboard shortcuts

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