pub struct HarnessEngine { /* private fields */ }Implementations§
Source§impl HarnessEngine
impl HarnessEngine
pub fn new() -> Self
pub fn task(&self, task_id: &HarnessTaskId) -> Option<&HarnessTaskV1>
pub fn run(&self, run_id: &HarnessRunId) -> Option<&HarnessRunV1>
pub fn grant(&self, grant_id: &SessionGrantId) -> Option<&SessionGrantV1>
pub fn operation( &self, operation_id: &HarnessOperationId, ) -> Option<&HarnessOperationV1>
pub fn execution_spec( &self, task_id: &HarnessTaskId, ) -> Option<&HarnessTaskExecutionSpecV1>
pub fn execution_specs( &self, ) -> impl Iterator<Item = &HarnessTaskExecutionSpecV1>
pub fn task_launch_issuance( &self, task_id: &HarnessTaskId, ) -> Option<&HarnessTaskLaunchIssuanceV1>
pub fn task_execution_spec_v2( &self, task_id: &HarnessTaskId, ) -> Option<&HarnessTaskExecutionSpecV2>
pub fn task_launch_issuances( &self, ) -> impl Iterator<Item = &HarnessTaskLaunchIssuanceV1>
pub fn task_execution_specs_v2( &self, ) -> impl Iterator<Item = &HarnessTaskExecutionSpecV2>
pub fn delivery( &self, delivery_ref: &HarnessDeliveryRef, ) -> Option<&HarnessDeliveryV1>
pub fn continuation( &self, continuation_ref: &HarnessContinuationRef, ) -> Option<&HarnessContinuationV1>
pub fn continuation_for_run( &self, run_id: &HarnessRunId, ) -> Option<&HarnessContinuationV1>
pub fn delivery_for_run( &self, run_id: &HarnessRunId, ) -> Option<&HarnessDeliveryV1>
pub fn tasks(&self) -> impl Iterator<Item = &HarnessTaskV1>
pub fn runs(&self) -> impl Iterator<Item = &HarnessRunV1>
pub fn grants(&self) -> impl Iterator<Item = &SessionGrantV1>
pub fn operations(&self) -> impl Iterator<Item = &HarnessOperationV1>
pub fn deliveries(&self) -> impl Iterator<Item = &HarnessDeliveryV1>
pub fn scheduler_pending_dispatch( &self, ) -> Result<Option<(&HarnessTaskV1, &HarnessRunV1, &HarnessOperationV1)>, HarnessEngineError>
pub fn scheduler_pending_dispatches( &self, ) -> Result<Vec<(&HarnessTaskV1, &HarnessRunV1, &HarnessOperationV1)>, HarnessEngineError>
pub fn scheduler_pending_dispatches_for( &self, operation_ids: &BTreeSet<HarnessOperationId>, ) -> Result<Vec<(&HarnessTaskV1, &HarnessRunV1, &HarnessOperationV1)>, HarnessEngineError>
Sourcepub fn scheduler_ready_task(
&self,
) -> Result<Option<&HarnessTaskV1>, HarnessEngineError>
pub fn scheduler_ready_task( &self, ) -> Result<Option<&HarnessTaskV1>, HarnessEngineError>
Finds the first Ready, dependency-satisfied task by walking every
stored task in order – there is no index by state, so this genuinely
scans. Refuses only once the walk itself has examined
HARNESS_SCHEDULER_SCAN_MAX tasks without returning; an eligible task
found earlier in the walk is returned regardless of how large the
store has grown.
Sourcepub fn scheduler_ready_task_by_id(
&self,
task_id: &HarnessTaskId,
) -> Result<Option<&HarnessTaskV1>, HarnessEngineError>
pub fn scheduler_ready_task_by_id( &self, task_id: &HarnessTaskId, ) -> Result<Option<&HarnessTaskV1>, HarnessEngineError>
Looks up one task by id and checks its own eligibility. The cost is
that task’s own dependencies and run_ids, never the size of the
store, so this does not consult any store-wide scan bound.
Sourcepub fn task_nonterminal_run_id(
&self,
task: &HarnessTaskV1,
) -> Result<Option<HarnessRunId>, HarnessEngineError>
pub fn task_nonterminal_run_id( &self, task: &HarnessTaskV1, ) -> Result<Option<HarnessRunId>, HarnessEngineError>
Walks one task’s own run_ids looking for a run that has not reached
a terminal lifecycle, returning its id – the run whose lifecycle
projection owns the task’s own state for as long as this keeps
returning Some (HarnessTaskMoveResultV1::TaskOwnedByLiveRun, D5:
while a run is non-terminal, a caller-initiated move that would change
its task’s state races the run’s own projection and never wins it
cleanly, so it is refused by name instead, naming this run). The cost
is that task’s own run_ids.len(), never the size of the store, so
this does not consult any store-wide scan bound.
Sourcepub fn task_has_nonterminal_run(
&self,
task: &HarnessTaskV1,
) -> Result<bool, HarnessEngineError>
pub fn task_has_nonterminal_run( &self, task: &HarnessTaskV1, ) -> Result<bool, HarnessEngineError>
Bare presence check built on task_nonterminal_run_id – most callers
(the scheduler’s own admission checks, operator_cancel_task/
operator_retry_task) only need to know whether a nonterminal run
exists, not which one.
Sourcepub fn unmet_task_dependencies(
&self,
task: &HarnessTaskV1,
) -> Vec<HarnessTaskId>
pub fn unmet_task_dependencies( &self, task: &HarnessTaskV1, ) -> Vec<HarnessTaskId>
The subset of task.dependencies that scheduler_task_is_eligible’s
dependencies_done check would treat as unmet – a dependency id that
does not resolve to a stored task, or one that resolves but has not
reached HarnessTaskStateV1::Done. This never decides admission itself
(that stays with scheduler_task_is_eligible, reached only through
scheduler_ready_task/scheduler_ready_task_by_id); it exists so a
caller that already knows a task was refused can name which specific
dependency id it is still waiting on instead of reporting a bare
ineligibility.
pub fn restore_deliveries( self, deliveries: Vec<HarnessDeliveryV1>, ) -> Result<Self, HarnessEngineError>
pub fn read_visibility( &self, grant_id: &SessionGrantId, ) -> Result<HarnessReadVisibilityV1, HarnessEngineError>
pub fn checkpoint(&self) -> HarnessEngineCheckpointV1
pub fn restore( checkpoint: HarnessEngineCheckpointV1, ) -> Result<Self, HarnessEngineError>
pub fn prepare( &self, mutation: HarnessMutationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_delivery( &self, delivery: HarnessDeliveryV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_continuation( &self, continuation: HarnessContinuationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_continuation_export( &self, expected_revision: HarnessRevision, continuation: HarnessContinuationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_continuation_export_begin( &self, expected_revision: HarnessRevision, continuation: HarnessContinuationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_continuation_export_outcome_unknown( &self, expected_revision: HarnessRevision, continuation: HarnessContinuationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_continuation_expiry( &self, expected_revision: HarnessRevision, continuation: HarnessContinuationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_accepted_spawn_continuation_bind( &self, expected_run_revision: HarnessRevision, run: HarnessRunV1, expected_operation_revision: HarnessRevision, operation: HarnessOperationV1, expected_continuation_revision: HarnessRevision, continuation: HarnessContinuationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_accepted_spawn_delivery_and_continuation_commit( &self, expected_run_revision: HarnessRevision, run: HarnessRunV1, expected_operation_revision: HarnessRevision, operation: HarnessOperationV1, expected_delivery_revision: HarnessRevision, delivery: HarnessDeliveryV1, expected_continuation_revision: HarnessRevision, continuation: HarnessContinuationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_delivery_stage( &self, expected_revision: HarnessRevision, delivery: HarnessDeliveryV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_accepted_spawn_delivery_commit( &self, expected_run_revision: HarnessRevision, run: HarnessRunV1, expected_operation_revision: HarnessRevision, operation: HarnessOperationV1, expected_delivery_revision: HarnessRevision, delivery: HarnessDeliveryV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_operation_transition( &self, expected_revision: HarnessRevision, operation: HarnessOperationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_run_operation_transition( &self, expected_run_revision: HarnessRevision, run: HarnessRunV1, expected_operation_revision: HarnessRevision, operation: HarnessOperationV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
Sourcepub fn prepare_run_event_commit(
&self,
operation: HarnessOperationV1,
expected_run_revision: HarnessRevision,
run: HarnessRunV1,
expected_task_revision: HarnessRevision,
task: HarnessTaskV1,
) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_run_event_commit( &self, operation: HarnessOperationV1, expected_run_revision: HarnessRevision, run: HarnessRunV1, expected_task_revision: HarnessRevision, task: HarnessTaskV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
Atomically records one run lifecycle event and projects it onto its task. The event operation is inserted exactly once; it is not the run’s original CreateRun operation.
Sourcepub fn prepare_run_incarnation_settlement(
&self,
operation: HarnessOperationV1,
expected_run_revision: HarnessRevision,
run: HarnessRunV1,
expected_task_revision: HarnessRevision,
task: HarnessTaskV1,
) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_run_incarnation_settlement( &self, operation: HarnessOperationV1, expected_run_revision: HarnessRevision, run: HarnessRunV1, expected_task_revision: HarnessRevision, task: HarnessTaskV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
Atomically settles one Running/Waiting run to the retryable
Failed lifecycle (HarnessFailureCategoryV1::TargetUnavailable,
retryable: true), its task to Failed, and drops the run’s own
binding: the node incarnation the binding named is gone, so there is
nothing left to bind to and nothing further this run will ever
report. OutcomeUnknown is deliberately not this event’s target –
that lifecycle names “we never learned whether the DISPATCH worked”
and ties to an originating operation that must itself be
OutcomeUnknown (validate_run_operation_coherence); a run reaching
this path already dispatched successfully and ran, so its
originating CreateRun operation is Succeeded and always will be,
making Failed (which validate_run_operation_coherence already
accepts against a Succeeded originating operation, the same way it
does for a rejected spawn) the coherent, truthful word for it. The
caller (hatchery-harness-service’s runtime) is the sole authority
for WHEN this is legitimate – this crate has no C2 client of its own
and never decides the trigger, only records the settlement once the
caller already knows the run’s bound incarnation is provably stale.
A dedicated function rather than a widening of
prepare_run_event_commit: this settlement’s authority shape and its
task-side sibling (validate_incarnation_settlement_task_projection)
stay independent of that function’s, even though both land the run on
Failed – see prepare_run_event_commit’s own doc comment. Same
CAS/idempotent-replay discipline as that function otherwise.
Sourcepub fn prepare_run_context_pack_record(
&self,
operation: HarnessOperationV1,
expected_run_revision: HarnessRevision,
run: HarnessRunV1,
) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_run_context_pack_record( &self, operation: HarnessOperationV1, expected_run_revision: HarnessRevision, run: HarnessRunV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
Narrow, single-entity, terminal-lifecycle-exempt mutation that records
a durable ContextPack receipt a run’s own session cleanly exported.
Deliberately does not call validate_run_lifecycle_transition (that
function rejects any mutation on a terminal run) and never touches
task state. Idempotent on the exact same receipt (a lost reconcile
race just replays); a second, different receipt is a hard conflict.
Sourcepub fn prepare_run_git_facts_record(
&self,
operation: HarnessOperationV1,
expected_run_revision: HarnessRevision,
run: HarnessRunV1,
) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_run_git_facts_record( &self, operation: HarnessOperationV1, expected_run_revision: HarnessRevision, run: HarnessRunV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
Narrow, single-entity, terminal-lifecycle-exempt mutation that records
a durable, one-shot git-facts capture of a run’s workspace. Structural
twin of prepare_run_context_pack_record; the only behavioral
difference is that this fact is legal to write exactly once —
validate_git_facts_recording treats any change to an already-Some
git_facts as a hard conflict regardless of cause (the A3 design has
no legitimate “second capture” scenario the way a context pack has a
legitimate re-export).
Sourcepub fn prepare_task_result_ref_record(
&self,
operation: HarnessOperationV1,
expected_task_revision: HarnessRevision,
task: HarnessTaskV1,
) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_task_result_ref_record( &self, operation: HarnessOperationV1, expected_task_revision: HarnessRevision, task: HarnessTaskV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
Genuinely new mutation (no A2 analog): grows one task’s result_refs
index by exactly one entry, attributing the growth to the exact run
whose already-committed result caused it. Never touches task.state
— the index is a passive fact about a task’s runs, not a task-state
transition, the same doctrine A2 held for run state. Idempotent on an
already-present ref, or on a task already at HARNESS_RESULTS_MAX
capacity: both replay cleanly rather than conflicting.
Sourcepub fn prepare_dispatch_outcome_commit(
&self,
expected_run_revision: HarnessRevision,
run: HarnessRunV1,
expected_operation_revision: HarnessRevision,
operation: HarnessOperationV1,
expected_task_revision: HarnessRevision,
task: HarnessTaskV1,
) -> Result<PreparedHarnessMutation, HarnessEngineError>
pub fn prepare_dispatch_outcome_commit( &self, expected_run_revision: HarnessRevision, run: HarnessRunV1, expected_operation_revision: HarnessRevision, operation: HarnessOperationV1, expected_task_revision: HarnessRevision, task: HarnessTaskV1, ) -> Result<PreparedHarnessMutation, HarnessEngineError>
Atomically records the categorical result of one leased CreateRun dispatch. Accepted outcomes use the authoritative spawn-proof seams.
pub fn accept(&mut self, prepared: PreparedHarnessMutation)
Sourcepub fn task_subtree(
&self,
root: &HarnessTaskId,
depth_bound: u16,
) -> BTreeSet<HarnessTaskId>
pub fn task_subtree( &self, root: &HarnessTaskId, depth_bound: u16, ) -> BTreeSet<HarnessTaskId>
The bounded set of task ids reachable from root by walking
parent_task_id downward – root itself is included. Mirrors
visible_runs_for_scope’s own Descendants shape (above) and its
HARNESS_CHILD_DEPTH_MAX-class bound, just walked over the task
graph’s own parent link instead of the run graph’s, and over
depth_bound rather than a fixed constant so a caller can choose
how deep this particular subtree check reaches. Unlike
visible_runs_for_scope, hitting the bound does not fail closed
with an error: this is a query, not an authorization decision by
itself, and the direction is safe either way it is used for one –
a task past the cut is simply absent from the returned set, which
is exactly the answer a caller checking subtree membership wants
for anything it cannot prove is inside (D5, Slice D:
ParentOutsideOwnSubtree / TaskOutsideOwnSubtree).
Sourcepub fn task_is_strict_descendant(
&self,
task: &HarnessTaskId,
root: &HarnessTaskId,
) -> bool
pub fn task_is_strict_descendant( &self, task: &HarnessTaskId, root: &HarnessTaskId, ) -> bool
Whether task is a strict (non-self) descendant of root –
task_subtree(root, HARNESS_CHILD_DEPTH_MAX) minus root itself,
the same depth fence the run graph’s own Descendants scope uses.
Sourcepub fn task_child_count(&self, root: &HarnessTaskId) -> u64
pub fn task_child_count(&self, root: &HarnessTaskId) -> u64
The number of tasks parented directly under root right now –
SessionContextV1::child_task_count’s own live observation, backing
g4a_context_get. Recomputed by scanning self.tasks on every call,
never a stored counter denormalised onto the task record (the owner’s
ruling behind that field’s own doc comment: detect a session’s
children, never cap them). Carries no upper bound of its own – a
task can parent arbitrarily many children and this simply reports
how many exist.
Sourcepub fn task_subtree_depth(&self, root: &HarnessTaskId) -> u64
pub fn task_subtree_depth(&self, root: &HarnessTaskId) -> u64
The depth of the deepest chain of tasks parented (transitively)
under root right now – SessionContextV1::child_task_subtree_ depth’s own live observation: 0 when root has no children, 1
when it has children but none of those have children of their own,
and so on. Walks parent_task_id downward the same way
task_subtree does, but returns the depth actually reached instead
of the set of ids, and – deliberately, unlike task_subtree – is
not bounded by HARNESS_CHILD_DEPTH_MAX or any other ceiling:
termination comes from self.tasks being finite (each pass either
inserts at least one task new to visible or the loop stops, and
visible can never hold more entries than self.tasks does), backed
by validate_task_cycles keeping the task graph a forest on every
mutation, not from a policy bound.
Sourcepub fn own_task_of_run(&self, run_id: &HarnessRunId) -> Option<HarnessTaskId>
pub fn own_task_of_run(&self, run_id: &HarnessRunId) -> Option<HarnessTaskId>
The task a run’s own grant governs – engine.run(run_id)?.task_id,
named so a caller deciding “is this the caller’s own task”
(HarnessTaskMoveResultV1::TaskIsOwn, D5) reads its intent rather
than reaching into HarnessRunV1 directly.
Sourcepub fn operations_for_task(
&self,
task_id: &HarnessTaskId,
limit: usize,
) -> Vec<&HarnessOperationV1>
pub fn operations_for_task( &self, task_id: &HarnessTaskId, limit: usize, ) -> Vec<&HarnessOperationV1>
Every persisted HarnessOperationV1 naming task_id, newest first
(created_at_unix_ms descending, ties broken by operation_id
descending so the order is deterministic), bounded by limit –
HarnessOperationV1.actor is stored today but had no read surface;
this lets the service render an operator-side ledger with the raw
actor for a given task.
Trait Implementations§
Source§impl Clone for HarnessEngine
impl Clone for HarnessEngine
Source§impl Debug for HarnessEngine
impl Debug for HarnessEngine
Source§impl Default for HarnessEngine
impl Default for HarnessEngine
impl Eq for HarnessEngine
Source§impl PartialEq for HarnessEngine
Manual, deliberately narrower than derive: equality is about the
durable task/run/operation/grant/… graph this engine carries, never
about mutation_generation or visibility_graph_cache, which are a
write-mutation counter and a read cache respectively – process-local
bookkeeping, not part of what makes two engines the same durable state.
Without this, two engines holding identical data could compare unequal
purely because one of them had served a read_visibility call and the
other had not.
impl PartialEq for HarnessEngine
Manual, deliberately narrower than derive: equality is about the
durable task/run/operation/grant/… graph this engine carries, never
about mutation_generation or visibility_graph_cache, which are a
write-mutation counter and a read cache respectively – process-local
bookkeeping, not part of what makes two engines the same durable state.
Without this, two engines holding identical data could compare unequal
purely because one of them had served a read_visibility call and the
other had not.