grid_runtime library

M3 runtime providers for the_grid — the layer that gives the_grid hands.

Ports gc's runtime.Provider contract (ADR-0004) into Dart, trimmed to what M3 consumes: Futures for acts (start/stop/interrupt), Streams for observations (a sealed RuntimeEvent stream + live session output). A SubprocessProvider (the Friday dogfood default) spawns a claude agent per ready bead in a git worktree, supervises it as a process group, and tracks the session as a the_grid-owned bead through the single bd write chokepoint (bd-only, --actor grid-controller, never SQL). A TmuxProvider over the standalone tmux package is the gc-compatible alternative. Layering follows predictable-flutter (Services → Repositories → Interactors → View); see docs/adr/ADR-0002 + ADR-0004 and docs/M3-BUILD-ORDER.md.

Track 2 built. The RuntimeProvider interface + RuntimeConfig / RuntimeEvent / RuntimeCapabilities value types + the SubprocessProvider impl (new-process-group spawn, explicit env allowlist, whole-tree kill) are implemented here.

Track 3 built. StationGitService gives git-worktree-per-bead isolation: Layer-1 root-checkout registration (probed default branch from origin/HEAD), Layer-2 git worktree add -b grid/<beadId> under <root>/.grid/worktrees/<rig>/<beadId>, the land step (commit → push → open PR via the injectable PrOpener, never auto-merge), and the VERBATIM gc safety: the three-gate fail-closed reaper, the GIT_* env blacklist on every exec, and the stale-ancestor guard.

Track 4 built. Lifecycle-as-beads + the single bd write chokepoint: a Dart port of gc's session state transition table (session_state.dart), the BeadOwnershipPredicate (the bead-shaped ownership gate sharing the rig allow-set with M2's OwnsSubstations), the StationBeadWriter chokepoint (fail-closed ownership re-check before EVERY create/update/close/delete, bd-only, --actor grid-controller), and the RuntimeActuator that consumes Track-2 RuntimeEvents and writes session beads THROUGH the chokepoint — including crash detection → restart / crash-loop quarantine.

Classes

AgentEnvAllowlist
The explicit parent-environment allowlist for a spawned agent child — the Dart port of gc's processenv.ProviderProcessPassthroughEnv (gascity/internal/processenv/provider.go:98-126).
BeadOwnershipPredicate
The bead-shaped ownership gate (ADR-0006 Decision 1; ADR-0000 A32) — the dispatch-side analog of the substation-ownership check grid_engine's convergence path applies to convergence beads.
BeadWorktree
A provisioned per-bead worktree — Layer 2 (ADR-0006 Decision 3). Plain value type. The dir name encodes the bead id so an orphaned worktree can be re-bound to its lifecycle bead on restart without external state (WorktreeLayout.beadIdFromName).
CrashDecision
What RuntimeActuator decided to do with a crashed session — surfaced so the dispatcher (Track 5) can re-spawn a restart or leave a quarantined session parked. Futures for acts, Streams for observations: this is returned by the act (onExited/onDied) AND emitted on decisions for observers.
DerivedRecord
One constructed record plus the substation its envelope must carry — what a BUILDER hands back to a caller that owns its own append.
ExternalCloseTerminalObligation
The external-close obligation (tg-ffl6; decision wave-2-flip-scope-soak-and-kill-date, Q6) — every session bead the LEDGER closed gets exactly one attempt.terminal, whatever the dual-read posture.
GhPrOpener
The real PR opener: shells gh pr create. Constructed ONLY by the live dogfood arming — the offline test suite always injects a fake. Kept tiny and over the GitRunner-style shell so it inherits no real-GitHub dependency in the type graph the tests exercise.
GitOps
Low-level git operations scoped to a working directory — the Dart port of gc's Git (gascity/internal/git/git.go), over the injectable GitRunner seam. This is a stateless Service in predictable-flutter terms (owns one source: the git binary); StationGitService composes it.
GitRunner
The git-command SEAM — the single point where StationGitService shells out to git. A reference type (carries the Runner role name; predictable-flutter).
GitRunResult
The result of one git invocation — stdout (combined with stderr, gc's CombinedOutput), the exit code, and a flag for whether the process even launched. Modelled as a plain value type (predictable-flutter: value types are plain).
GitWorktree
One git worktree entry, parsed from git worktree list --porcelain. Plain value type (predictable-flutter). gc's git.Worktree (internal/git/git.go:13-18).
GridIssueTypes
the_grid's registered custom issue-type vocabulary.
GridReadyWorkSource
The live ReadyWorkSource over a beads_dart GridControllerRuntime.
IncarnationEnv
The per-incarnation environment a live agent session receives from the controller — the_grid's GRID_* analog of gc's session.RuntimeEnv (gascity/internal/session/lifecycle.go:30-67), trimmed to the four vars M3 needs (M3-BUILD-ORDER Track 2).
LandResult
The result of the land step (DIVERGES from gc; ADR-0006 Decision 3): commit → push → open PR. Carries either the PullRequestRef or a failure reason so the caller records the outcome on the lifecycle bead.
LivenessDetectorObligation
§2.4 obligation 3 — the liveness detector: beats into traj_pulse, threshold transitions into the log.
PrimaryCheckoutFreshness
Immutable result of inspecting one Layer-1 primary checkout.
ProcessGroupController
The OS process-group SEAM — the single point where SubprocessProvider touches process signalling and pgid resolution. A reference type (carries the Controller role name; predictable-flutter).
PrOpener
The PR-opener SEAM — the single point where the land step opens a pull request. INJECTABLE so the whole land path (commit → push → open PR) runs offline against a fake that records the branch it was asked to open (Fakes, not mocks). A reference type (the Opener role name; predictable-flutter).
PrOpenFailure
Why a PR open did not produce a PullRequestRef. Modelled as a sealed-ish value so the land step can record the failure on the lifecycle bead rather than throwing.
PullRequestRef
A reference to an opened pull request — what the land step records on the lifecycle bead (ADR-0006 Decision 3). Plain value type (predictable-flutter).
PullRequestResult
The result of PrOpener.open: either the ref or a failure. A tiny sealed union via a record-style holder (kept simple; no freezed needed for two branches consumed at one call site).
QuarantineSession
The session crashed too many times in the window — quarantined. The bead is parked at state=quarantined with quarantine_cycle/quarantined_until (gc's QuarantinePatch); the dispatcher does NOT re-spawn it.
ReadyWorkSource
The dispatch read seam over beads_dart's reactive surface (M3 Track 5; ADR-0006 Decision 1) — a second consumer of the same observable surface grid_engine's convergence path reads. The DispatchInteractor attaches as a SECOND consumer of the same observable surface M2 uses; it does not go through reduce→gate→actuate.
ReapOutcome
The outcome of a reap attempt — distinguishes a clean removal, a permitted preview, and a fail-closed REFUSAL, so the caller can assert WHY a worktree was removed or kept. Every successful outcome preserves the three observed gate values, including known-present values permitted by the bounded operator override.
RestartSession
The session should be restarted: a fresh incarnation. The bead is NOT closed; restart_requested is set so the dispatcher re-spawns (gc's RequestFreshRestart, manager.go:867-879).
RootCheckout
The Layer-1 root checkout registration — a the_grid-OWNED real clone of the target repo (lenny), registered ONCE, with origin set and the default branch probed from origin/HEAD (ADR-0006 Decision 3; gc's substation model). This is NOT a worktree; it is the_grid's "rig" in gc's sense.
RuntimeActuator
The bd write chokepoint consumer (M3 Track 4): turns Track-2 RuntimeEvents into state transitions on the_grid-owned session beads, written exclusively through the StationBeadWriter chokepoint (bd-only, --actor grid-controller, fail-closed ownership re-check before every write).
RuntimeCapabilities
What a RuntimeProvider can reliably detect, so callers degrade explicitly instead of assuming — gc's ProviderCapabilities (runtime.go:197-199 Capabilities()), as a record-style freezed value.
RuntimeConfig
Parameters for starting one agent session — the Dart port of gc's runtime.Config (runtime.go:459-578), trimmed to M3 (M3-BUILD-ORDER Track 2): the overlay/pack/MCP/T3/fingerprint/dialog machinery is CUT (reference only). What survives is exactly what SubprocessProvider needs to spawn a claude per ready bead in its worktree.
RuntimeEvent
An observation from a RuntimeProvider's session lifecycle, emitted on the events stream (Streams for observations; APIs convention, CLAUDE.md).
RuntimeProvider
Manages agent sessions — the Dart port of gc's runtime.Provider (gascity/internal/runtime/runtime.go:107-200), trimmed to M3 (M3-BUILD-ORDER Track 2). A reference type (the Provider role name; no extra classifier — predictable-flutter).
SessionClosure
What the LEDGER says about one session bead's closure — the one bd fact the external-close obligation consumes (decision wave-2-flip-scope-soak-and-kill-date, Q6: bd remains an input to terminal truth). A null answer from a SessionClosureProbe means "open, or not in the snapshot" — nothing to heal.
SessionParked
The session ended cleanly — no restart, no quarantine. The lifecycle bead is transitioned to asleep (a clean exit) or closed (the caller's terminal choice via RuntimeActuator.closeSession).
SpawnedProcess
A handle over one spawned agent process — the seam's return value, so a fake can synthesize stdout/stderr streams and an exit signal without a real OS process.
StationBeadWriter
StationGitService
The Service that gives the_grid git-worktree-per-bead isolation (M3 Track 3; ADR-0006 Decision 3). Stateless IO over the injectable GitRunner + PrOpener seams (predictable-flutter: a Service owns one source — here the git binary + the PR-open boundary — and is constructed with its dependencies). Futures for acts (register/provision/land/reap); point-in-time list is a Future too (a read act, not an observation stream).
StationTrajectoryRecorder
The engine-side derivation layer (stage1-wiring §2), constructed by the harness and injected everywhere as an OPTIONAL collaborator: disabled or degraded it is a counting no-op, and no call site ever branches on "is the trajectory up" (§1.1).
StuckObligationAccountant
Counts consecutive refusing passes per obligation and files the note.
SubprocessProvider
SubprocessSpawner
The Process SEAM for spawning agents — the single point where SubprocessProvider touches Process.start. Mirrors beads_dart's BdRunner: the real impl (SystemSubprocessSpawner) spawns; tests inject a fake that returns a programmed handle, so the supervision/event/env logic runs offline (Fakes, not mocks). A reference type (the Spawner role name).
SystemGitRunner
The real seam: execs git with the blacklist stripped and combines stdout+stderr. The ONLY place this file touches dart:io process spawning.
SystemProcessGroupController
The real seam: resolves pgid via ps, probes liveness with a harmless signal, and signals groups via Process.killPid(-pgid, …).
SystemSubprocessSpawner
Spawns real agent subprocesses via dart:io with the Track-2 contract.
TrajectoryAckRecordSink
The acknowledgement-capable extension used only by decision-bearing recorder observations.
TrajectoryAppendResult
The completed disposition of a decision-bearing trajectory append.
TrajectoryRecord
One trajectory record, pre-envelope: the typed fact plus the identity grammar. The service stamps everything else (§2.6 rule 7).
TrajectoryRecorderStats
A recorder status read — plain counters for the /status trajectory block.
TrajectoryRecordSink
The enqueue-only handle to the harness's bounded append queue (§2.5).
UnknownTerminalSettlementObligation
§2.4 obligation 1 — settle attempt.terminal(outcome='unknown') rows that no settling successor has healed.
WorktreeLayout
Pure helpers for the <root>/.grid/worktrees/<substation>/<beadId> layout + grid/<beadId> branch naming — mirrors gc's .gc/worktrees/<substation>/<name> (internal/workdir/workdir.go:76-86). Separated out so the path/branch derivation and the bead-id round-trip are unit-tested with no IO.
WorktreePulseScanner
Walks each live worktree's .grid and reports the newest file mtime.
WorktreeReapedBackfillObligation
§2.4 obligation 2 — backfill the worktree.reaped record the non-atomic crash class lost.
WorktreeScan
A scan's beats plus its cost.
WorktreeScanCost
One scan's measured cost — the in-budget check's raw material.

Enums

AdoptOutcome
GateCloseCause
Durable values for grid.gate.close_cause.
GateOutcome
The outcome of one of the three pre-removal safety gates. Distinguishes a clean "no" from a fail-closed "couldn't tell, assume unsafe" so callers (and tests) can assert WHICH rung tripped and that a probe ERROR is treated as unsafe — not silently as safe. gc collapses this into a bool that returns true on probe error (git.go:146-152,166-172); we keep the distinction explicit because fail-closed-on-probe-error is the load-bearing invariant.
GateSweepSessionDisposition
The A48 session disposition supplied to a terminal gate sweep.
GroupTerminateResult
The result of a terminateGroup escalation, so the caller (and a test) can assert which rung fired without scraping logs.
LeaseDisposition
Lifecycle
The expected lifetime of a runtime command — gc's runtime.Lifecycle (gascity/internal/runtime/runtime.go:451-457), trimmed to the two M3 cases.
LifecycleCommand
What triggered a state change — the verb the runtime invoked, not the resulting state (gc's TransitionCommand vocabulary, state_machine.go).
MintPhase
OperatorBeadTextField
The single bd write chokepoint (ADR-0006 Decision 2; ADR-0000 A32) — the ONLY path through which the_grid's session/lifecycle/recovery beads are written, wrapping the M2 BdCliService.
PrimaryCheckoutState
Classified state of one Layer-1 primary checkout.
RoundRetireCause
attempt.round.retired cause — void is the Dart keyword, hence voided.
StepFailureClass
TrajectoryProvenance
provenance ENUM (§8 Q18).

Extension Types

LifecycleState
The fine-grained session lifecycle state stamped on metadata.state.

Extensions

GridIssueTypeClassification on IssueType
the_grid-only classifications over beads' open IssueType.

Constants

gitEnvBlacklist → const Set<String>
The git environment variables that MUST be stripped before every git exec so a subprocess git command uses the intended cwd, not a parent repo's GIT_DIR/GIT_WORK_TREE. Verbatim from gc's gitEnvBlacklist (gascity/internal/git/git.go:285-301). the_grid is itself a git repo invoked from melos/hooks, so this leak is real, not theoretical.
gridRuntimeScaffold → const String
The package's identity, exposed so the empty scaffold has a referenced symbol and downstream wiring can assert the package is on the path before Track 2 lands. Replaced by the real runtime surface in Track 2.
kDefaultExternalCloseGrace → const Duration
How long a ledger-closed session must stay closed-in-bd / open-in-P1 before the external-close obligation appends its reconstructed terminal. Every NORMAL terminal transits that state briefly — bd is written first and the record appended after — so an eager heal would race the real record (r8 — V2-B1). The comparator's heal uses the same 90 s.
kDefaultLivenessThreshold → const Duration
How stale a beat must be before the detector calls the attempt LOST. The house's sustained-stall threshold (kDefaultWedgeThreshold), reused deliberately: the two answer the same operator question at the same scale.
kDefaultPulseCoalesce → const Duration
Beats coalesce per subject (schema §4: traj_pulse is ≥30s per subject), so a 30 s tick does not rewrite the same row on every pass.
kDualReadRoundSummaryChannel → const String
The SECOND attempt.note channel, added by wave 1's C2 (cut-wiring §0.4) — the durable dual-read round summary. Stage-1's §2.3 statement that the obligation channel is the only armed one is a STATED EXTENSION here, not a slip: the doc amendment rides C2's PR.
kExitOutputHeadChars → const int
How much of an exited session's transcript RuntimeProvider.exitOutputOf retains, measured in code points.
kExitStatusFileEnv → const String
The env var naming the per-session file the REAPER PARENT writes the real leader exit code into. SubprocessProvider.start sets it (the provider owns the path); SystemSubprocessSpawner.spawn reads it to decide whether to compose the reaper; the provider reads the FILE on vanish. Absent or empty ⇒ no reaper is composed and the spawn is byte-for-byte what it was before, so any caller outside the provider is unchanged.
kExternalCloseTerminalObligation → const String
kExternalCloseUnknownReason → const String
unknown_reason for the terminal-reconcile heal: the ledger says closed and no station bd write exists for it. A record about a fact the station OBSERVED in the ledger — which is what an observer append is.
kGitRootGuardExitCode → const int
The exit code a GitOps work-tree-root refusal carries. Negative, so it can never collide with a real git status, and distinct from the runner's non-launch sentinel (-1) so a refusal is legible as such in a log.
kLegacyAttemptCountKey → const String
The mount-attempt bead's durable counter key — wire-identical to grid_engine's MountAttemptKeys.count, duplicated because grid_runtime cannot import grid_engine (the same split the molecule join keys live under). The recorder reads it into legacy_attempt_count, the shadow-comparable ordinal traj shadow-diff joins against the legacy bead (§2.2, r2 major 8).
kLivenessDetectorObligation → const String
kObligationBatchSize → const int
Rows per obligation pass. A pass is bounded so one storm-sized backlog cannot own the tick; the remainder rides the next pass (and runToFixpoint keeps passing while a pass makes progress).
kObligationStuckChannel → const String
The one attempt.note channel armed at Stage 1 (§2.3): the tick's stuck-obligation accounting (schema §5's N-failure rule). The Q5 content-split for agent journaling is deferred.
kOrphanGrace → const Duration
How long a session whose LEADER is gone but whose OWNED process group still has live members is given to drain before that group is signalled. Generous on purpose: a legitimately-backgrounded flush deserves to finish, and the session cannot advance the circuit while the grace runs anyway.
kPreStage3GrantBasis → const String
The grant_basis payload marker on Stage-1 pre-grant ids (§2.2): no grants exist before Stage 3, so the recorder mints a placeholder ULID per mount and says so. At Stage 3 the real admission.grant.issued takes over the same slot.
kPulseViaRuntime → const String
traj_pulse.observed_via for the provider's activity poll.
kPulseViaWorktreeMtime → const String
traj_pulse.observed_via for the worktree .grid mtime scan.
kReaperScript → const String
The REAPER PARENT script. detachedWithStdio buys the process group but costs the exit code (Process.exitCode throws for a detached process), so a vanish had to be INFERRED — and a murdered agent vanishes exactly like a finished one. This wrapper IS the leader: it runs the harness as its child in the SAME group, WAITS for it, writes the real code, and exits with it.
kReconcilerMintedAttemptBasis → const String
attempt_id_basis for a settlement whose session predates Stage 1 — no attempt_id breadcrumb exists, so the reconciler path mints one (§2.1's bounce rule); such sessions are outside the shadow's comparable set.
kRecorderCacheBound → const int
The FIFO bound on every warm cache the recorder keeps. Epoch-truncate by insertion order: Dart maps and sets iterate oldest-first, so dropping keys.first retires the coldest entries. Sized generously against the station's real storm (a handful of concurrent sessions).
kRecorderMintedAttemptBasis → const String
attempt_id_basis for the defensive fallback: a terminal observed for a session the recorder never saw minted and nobody seeded (should not happen on a healthy boot — recovery seeds the cache first). Non-fatal law: mint and mark rather than refuse.
kRestartReconcilerBasis → const String
provenance_basis for the teardown-replay observer append (cut-wiring §C2, r5): the reconciler closed an OPEN session bead and emitted no terminal, so the head would stay open forever. Reconstructed testimony about a session whose attempt this pass never observed — outcome='settled' stays reserved for the settle arm, which EARNS it by joining the attempt row.
kStuckObligationThreshold → const int
Schema §5's N.
kTeardownReplayUnknownReason → const String
unknown_reason for the teardown-replay observer append — the schema's explicit-unknown vocabulary (ck_unknown requires a reason).
kTerminalReconcileBasis → const String
provenance_basis AND idem grammar for the bridge-homed terminal-reconcile heal (cut-wiring §C2, r6–r11): its OWN named basis, because ck_prov requires one and this writer is not the reconciler.
kTickReapedBackfillBasis → const String
provenance_basis for the tick's worktree.reaped backfill (§2.4 obligation 2): the legacy reap already ran, the record never landed — the named non-atomic crash class, healed record-only.
kTickUnknownSettlementBasis → const String
provenance_basis for the tick's settling terminal (§2.4 obligation 1): an unknown terminal healed from a process/worktree probe.
kUnknownTerminalSettlementObligation → const String
Obligation names — stable identifiers for the tick's telemetry and for the stuck-obligation accounting (schema §5).
kUnownedSubstation → const String
The substation stamped when no known prefix owns a work bead id (§2.2, r2 minor 12) — deterministic, never CHECK-refused, so ck_substation's presence rule cannot turn an unowned id into a permanent clean-round blocker.
kUnownedSubstationBasis → const String
The payload marker accompanying kUnownedSubstation (substation_basis).
kWorktreeReapedBackfillObligation → const String
kWorktreeStateDirName → const String
The per-worktree state directory the scanner reads. .grid inside the worktree — the SESSION's artifacts, not the grid home's store.

Functions

allowedCommands(LifecycleState from) List<LifecycleCommand>
The commands legal from from (gc's AllowedCommands), sorted by name for a stable rendering — useful for diagnostics / "what can happen next?".
buildStage1ObligationQueries({required StationTrajectoryRecorder recorder, required TrajectoryDb db, required String station, required int bootEpoch(), LastActivityPoll? lastActivity, SessionClosureProbe? sessionClosure, AppendQueuedProbe? appendQueued, WorktreePulseScanner scanner = const WorktreePulseScanner(), ProcessGroupController? processes, Duration livenessThreshold = kDefaultLivenessThreshold, Duration pulseCoalesce = kDefaultPulseCoalesce, Duration externalCloseGrace = kDefaultExternalCloseGrace, DateTime clock()?}) List<ObligationQuery>
Builds the Stage-1 obligation set, in §2.4's order.
cleanGitEnvironment(Map<String, String> parentEnv) Map<String, String>
Builds the clean child environment for a git exec: every entry of parentEnv EXCEPT the gitEnvBlacklist keys (gc's git.go:314-320). Pure over an injected map so the blacklist is unit-tested with a fake env.
establishStationProcessGroup({required int stationPid, ProcessGroupController controller = const SystemProcessGroupController(), SetSidCall setSid = _systemSetSid}) Future<int>
Makes stationPid the leader of a new session and process group.
exitOutputHead(String output) String
Returns the bounded diagnostic head of output without splitting a code point.
gateBlocks(GateOutcome outcome) bool
Whether GateOutcome blocks removal — both GateOutcome.present and GateOutcome.probeError block; only GateOutcome.clear permits.
gateCloseCauseOf(Bead gate) GateCloseCause
Reads a gate's durable close-cause vocabulary.
isStrictlyUnderDir(String dir, String path) bool
Whether path is strictly contained within dir — the scope gate that guarantees the reaper can only ever delete inside the_grid's own worktrees root. gc's isStrictlyUnderDir (cmd/gc/bead_worktree_reaper.go:191-198).
newAttemptId() String
Mints an attempt_id — the trajectory log's CHAR(26) name for ONE process incarnation (stage1-wiring §2.1; schema §3's one-attempt-one-incarnation).
newInstanceToken([Random? random]) String
A cryptographically random 16-byte hex token for fencing drain/stop and async delivery against a stale session incarnation — gc's session.NewInstanceToken (lifecycle.go:21-27).
parseWorktreeList(String output) List<GitWorktree>
Parses git worktree list --porcelain output. Each block is separated by a blank line: worktree <path>, HEAD <sha>, branch refs/heads/<name>. gc's parseWorktreeList (git.go:331-360).
sessionDispositionOfMetadata(Map<String, dynamic> metadata) GateSweepSessionDisposition
Derives a session's disposition from its OWN metadata alone.
stationNoteSubject(String station) String
The note's subject when a refusal names no session — which is the norm: an obligation's SQL or repair fails wholesale, for no one session. The station is the honest subject, and the shape keeps the note's note:<subject>:<n> key well-formed and greppable.
systemEnvironment() Map<String, String>
The live process environment as a plain map. Wrapped so callers and tests share one read point (and so a test can prove a real exported GC_DOLT_PASSWORD is filtered by running AgentEnvAllowlist.build over this map).
terminateGroup({required ProcessGroupController controller, required int pgid, required int leaderPid, Duration grace = const Duration(seconds: 2), Duration pollPeriod = const Duration(milliseconds: 25)}) Future<GroupTerminateResult>
Sends SIGTERM to pgid, polls for the group to exit within grace, then escalates to SIGKILL — gc's processgroup.Terminate (processgroup_unix.go:53-68), as a free function over the injected ProcessGroupController seam.
transition(LifecycleState from, LifecycleCommand command) LifecycleState
Validates the transition and returns the new state, throwing IllegalLifecycleTransition when disallowed (gc's Transition).
transitionOrNull(LifecycleState from, LifecycleCommand command) LifecycleState?
Validates that applying command to a session in from is legal and returns the new state, or null when the transition is disallowed (the non-throwing analog of gc's Transition).
validateAncestorWorktreesNotStale(String path) StaleAncestorRejection?
Walks path's ancestor chain and returns a rejection reason when any ancestor has a regular-file .git worktree pointer whose gitdir: target is unusable — the VERBATIM port of gc's ValidateAncestorWorktreesNotStale (gascity/internal/workdir/workdir.go:303-359). Returns null when safe.

Typedefs

AppendQueuedProbe = bool Function({required String attemptId, required String sessionId})
The harness's answer to "is an append for this attempt, or a terminal for this session, still queued or mid-flight?" The heal must not race a terminal record that is about to land (r8 — V2-B1) — and it must ask by SESSION too, because the head's attempt id is the spawn's while an observed session terminal carries the recorder's per-session id.
GateAutoCloseReceipt = ({GateCloseCause cause, String gateId, String sessionId})
One newly closed gate.
LastActivityPoll = DateTime? Function(String providerName)
The last-activity poll (RuntimeProvider.lastActivity) — liveness surface (b) of §2.3. Keyed by the provider's session name, <sessionId>/<stepPath> (AllocationAddress.providerName).
SessionClosureProbe = SessionClosure? Function(String sessionId)
The engine-side answer to "is this session bead closed in bd?" — read off the state snapshot the join bridge already holds in memory (one lookup per row per tick, never a bd round trip). Null when the seam is unwired (a bare harness) or the bead is open/unknown.
SetSidCall = int Function()
Injectable POSIX setsid() call used by establishStationProcessGroup.
StaleAncestorRejection = String?
Result of validateAncestorWorktreesNotStalenull when the spawn is safe, or a human-legible rejection reason when an ancestor has a stale worktree pointer.
TrajectoryRecorderFlare = void Function(String name, Map<String, String> data)
The flare seam — shape-compatible with ExplorationTransport.flare (and with the harness's rate-limited flare, which is what production passes).

Exceptions / Errors

IllegalLifecycleTransition
Raised when transition is asked for a (state, command) pair the table does not allow — the analog of gc's ErrIllegalTransition. Callers either guard with transitionOrNull or treat this as a programmer error.
OwnershipGuardRefused
Raised when bd refuses an ownership-sensitive conditional update.
OwnershipRefused
Raised when the StationBeadWriter chokepoint refuses a write because the target bead's substation is absent or not in the shared allow-set (fail-closed).
SessionAlreadyExists
Thrown by RuntimeProvider.start when a live session already holds the requested name — gc's ErrSessionExists (runtime.go:22-24).
SessionClosedRefused
Raised when StationBeadWriter refuses to mint or refresh a gate for a session bead that the state snapshot already shows as closed.
SessionNotWritable
Refuses interaction with an unknown, one-turn, or terminal session.