Metadata-Version: 2.5
Name: kestrel-feature-workflows
Version: 0.7.4
Summary: First-class agent workflow orchestration primitive for Kestrel Sovereign
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: <3.15,>=3.11
Requires-Dist: aiosqlite>=0.21.0
Requires-Dist: jsonschema>=4.20
Requires-Dist: kestrel-sovereign-sdk<1,>=0.36.0
Requires-Dist: kestrel-sovereign<1,>=0.53.31
Requires-Dist: tzdata>=2026.3
Provides-Extra: test
Requires-Dist: prometheus-client>=0.20; extra == 'test'
Requires-Dist: pytest-asyncio>=1.1.0; extra == 'test'
Requires-Dist: pytest-timeout>=2.3.1; extra == 'test'
Requires-Dist: pytest>=8.0.0; extra == 'test'
Description-Content-Type: text/markdown

# kestrel-feature-workflows

First-class agent workflow orchestration for Kestrel Sovereign.

The package also installs a host-scoped `WorkflowsHostFeature` that owns the
durable, engine-neutral operator run plane. It registers the public SDK
`RunService` at host scope as `workflows.runs` version `1.1.0`, persists
accepted launches and their recovery outbox in the host database, and exposes
a fenced producer lifecycle for installed execution features. The run plane
does not add HTTP routes or engine-specific fields.

Absolute artifact links fail closed unless their exact HTTPS origins are
listed in the package-owned `KESTREL_WORKFLOWS_ARTIFACT_ORIGINS` environment
variable as a JSON array, for example
`["https://artifacts.example.com","https://cdn.example.com:8443"]`. Entries
must be exact HTTPS origins: paths, queries, fragments, credentials, and
non-HTTPS URLs are rejected. The value is limited to 16 KiB, 100 origins, and
2,048 characters per origin. Canonical `/authorized/artifacts/<artifact_id>`
links remain same-origin and need no allowlist entry.

Alternate hosts may instead provide the existing
`workflows.artifact_origins` context mapping. If both sources are present,
their normalized origin sets must be identical or host-feature startup fails;
otherwise the environment source is used when set. Malformed values fail
startup without logging their contents.

Workflows is orchestration **on top of** the existing Signal Dispatcher. Stages
dispatch signals (`ACTION` / `ARTIFACT` / `COGNITION`); durability, dedupe,
locks, causation tracking, retention, and redaction all come from the
dispatcher. Workflows adds what the dispatcher lacks: multi-stage sequencing and
fan-out, per-stage gates (including an adversarial `red_team_clear` gate),
reverse-order saga compensation, a cancellation barrier, DID-signed versioned
workflow definitions, and constitutional-boundary enforcement.

Missing signed output-projection values fence compensation: the undo action
cannot substitute original input identifiers for a forward effect's output.
The committed forward-effect receipt remains durable and recovery records
`effect_output_projection_invalid` for operator reconciliation.

Execution is lease-owned: runnable runs and open stage/compensation attempts
are atomically claimed by an executor and heartbeated. Recovery reuses the
persisted attempt idempotency key and dispatch linkage; it advances confirmed
effects, never reruns completed stages, and fails safely when an external
effect cannot be determined. This provides exactly-once workflow transitions
and at-most-once effects where downstream idempotency supports it, not a
blanket exactly-once guarantee for arbitrary external systems.

### Declared runtime triggers

`WorkflowSpec.triggers` is honored at runtime for `manual`, `cron`, and
`signal_source` declarations. Manual behavior is unchanged. A non-manual
definition is rejected before persistence when its static trigger parameters
do not satisfy `params_schema`, its signal source is not registered, or the
required released Core capability is absent.

Cron declarations are registered only through SchedulerFeature's public
`schedule_add` / `schedule_list` / `schedule_remove` contract. They run in the
signed IANA `timezone_name` (UTC when omitted for backward compatibility) with
`misfire_policy="skip"`; each callback must carry Scheduler's public,
non-forgeable execution identity. The scheduled occurrence time, not callback
time, is part of the deterministic workflow launch identity. Signal-source
declarations use SignalDispatcher's public agent-scoped durable consumer
registration and claim/lease/ACK/NACK lifecycle. Provider `source_event_id`
deduplication and the normalized durable event ID make redelivery converge on
one workflow run. A versioned agent/source boundary is captured before the
definition and desired registration commit, so retained history does not
launch retroactive runs while post-commit events survive registration/restart
windows.

Timezone names must use the canonical case-sensitive IANA spelling (for
example, `America/Chicago`). New definitions are validated against the
installed `tzdata` release (version 2026.3 or newer). Scheduler execution and
reconciliation use Core's host timezone resolver, including system zoneinfo.
Deployments should keep installed timezone data consistent across executors.
During a rolling Workflows upgrade, all executors reconciling the same scope
must run version 0.7.0 or newer before admitting a definition with an explicit
non-UTC `timezone_name`. A pre-0.7.0 reconciler drops that signed field while
rebuilding desired state, hits `trigger registration identity conflict`, and
aborts reconciliation for the entire owner/dispatcher scope. The existing
schedule remains intact, but retirement, drift repair, restart adoption, and
health updates do not converge until every reconciler is upgraded.

The package persists an owner-and-live-dispatcher-scoped desired-state ledger
for every public registration. Definition writes, startup, soft re-enable,
revoke, feature disable, and feature removal reconcile that ledger. Retirement
intent is committed before the external resource is removed or deactivated;
publication identity is committed before SignalDispatcher registration and
Scheduler rows are adopted from their exact public arguments/idempotency key
after an ambiguous add result. This closes the supported cross-store crash
windows without reading Scheduler or SignalDispatcher private tables and
without claiming a transaction across their stores.

### Signed execution context and action outputs

A stage may explicitly set `include_execution_context=true` to receive a
reserved `workflow_execution` object containing its stable run ID, stage name,
attempt number, and stage idempotency key. Since 0.7.1 it also carries the
run's persisted trigger provenance: `trigger_kind` (`manual`, `cron`, or
`signal_source`) and `trigger_registration_id` (`null` for manual runs). A
source can therefore tell an unattended tick from an operator launch without
trusting a run parameter; executors older than 0.7.1 omit both keys. Stages
that do not opt in receive no new payload fields. A signed `output_projection` maps bounded RFC-6901 pointers in
an action result to run-parameter names. It is supported on gates that settle
in the dispatch attempt; pending gates (`await_signal`, `consent_collect`, and
`council_approve`) reject it at definition time. Projected JSON is persisted
with the public effect receipt, and the successful stage transition publishes
those parameters atomically, so subsequent stages and `await_signal` context
materialization see the same values after normal execution or crash recovery.
Reserved workflow identity parameters in legacy stage, gate, or declared
trigger params are ignored at dispatch; new manual launch params, merge
targets, and projection targets reject them. This preserves old signed
definitions without permitting them to forge execution identity. The additive
`workflow_stage_links.effect_output_params_json` column is installed
idempotently at initialization, with `{}` as the rolling-upgrade default.
Before admitting a definition that uses `include_execution_context` or
`output_projection`, every definition, run, and recovery executor in that
owner scope must run Workflows 0.7.0 or newer. A pre-0.7.0 recovery executor
drops either signed field while verifying the pinned definition, claims the
expired run, and terminally fails it as `recovery_error_no_safe_resume`
without compensating already-completed stages.
Cron timezone names are checked against the installed `tzdata` catalog when a
new definition is admitted. Persisted signed definitions remain loadable if a
later catalog removes an alias; reconciliation then marks only that scheduler
registration unhealthy and removes its stale schedule without failing live
workflow runs.

Signal trigger delivery is drained in bounded pages by the feature's existing
supervised lease-recovery cadence; declared triggers add no second polling
task. SchedulerFeature remains the cron wake owner and SignalDispatcher remains
the normalized-signal/durable-delivery owner. The default cadence can add up to
roughly ten seconds of signal-trigger launch latency. A trigger run persists
its registration, delivery/event or schedule identity, deterministic
idempotency key, and causation evidence before the transport is ACKed or the
Scheduler callback succeeds. A crash after that handoff is recovered through
the ordinary workflow run lease.

Signal events do not implicitly become workflow input. Only the trigger's
signed, static `params` are passed as `run.params`; triggering event data is
not projected into `run.params`. This includes its payload, caller identity,
and event identity. Event and delivery identifiers remain available as run
causation and inspection evidence. A future payload mapping must be an explicit
signed, schema-validated declaration; this release never merges untrusted event
data into stage parameters.

`workflow_list_definitions` includes registration state and
`workflow_inspect_definition` returns `trigger_health`, lifecycle state, last
error, and the last delivered event/run identity. Unhealthy registration or
cleanup is returned as a partial tool result rather than hidden. Owner DID,
live agent/dispatcher DID, definition/version/hash, and public resource identity
are checked again at every callback and delivery; a scope mismatch is never
reassigned to the current user.

`workflow_inspect_retention` exposes only the live owner's durable retention
debt. A terminal run missing its exact owner/name/version definition is retained
until that signed definition is restored; the next sweep clears the receipt
set-wise and applies the restored retention policy. This avoids guessing a
retention period or deleting another tenant's evidence.

See [the trigger architecture and migration notes](docs/architecture/WORKFLOW_TRIGGERS.md)
for identities, crash windows, and operational behavior.

Workflows persists the public durable-admission disposition and terminal
`SignalResult` for each await effect. Core 0.53.3 has no public historical
effect-status lookup, so a process loss after admission but before that result
is persisted remains durably `COMPENSATING` unless the host supplies
`workflow_effect_status_resolver` backed by authoritative public effect
evidence. Workflows never queries Core's private `signal_log` table to guess.

### Durable `await_signal` gates

An effect stage may use an `await_signal` gate to dispatch once, then wait for
an authenticated Core signal without retaining an asyncio task. The gate requires a
registered source, absolute timeout, `matcher_version: 1`, bounded `all`/`any`
matcher (`eq`, `in`, `exists` over JSON Pointers), and optional
sanitized-payload projection. Only
the closed `gate.passed` branch is permitted: its true target is the signal
path and its false target is the timeout path. Workflows persists the consumer,
tenant/owner scope, frozen context operands, deadline idempotency key, and
terminal evidence. Immediately before dispatching the external stage effect,
Workflows captures Core 0.53.3's public `DurableSourceBoundary` for the exact
agent/source scope and commits its complete versioned record in the wait row.
The row remains in `boundary_captured` setup state until effect admission; a
restart reuses it and never captures a later replacement. A claimed delivery
and the scheduler deadline race through one store transaction, so a late or
duplicate delivery can be audited but cannot replay the effect or graph
transition.

Core 0.53.3 provides the durable boundary and delivery lifecycle, but its
`DurableSignalEvent` does not persist an immutable, authenticated receipt of
the sanitizer and effective trust policy that applied at ingress. A sanitizer
registered today is not proof about a retained historical event. Therefore
Workflows 0.6.0 fails closed before the await effect dispatches unless the host
provides `workflow_await_signal_event_trust_verifier`, backed by a newer public
Core per-event attestation contract. Every delivered receipt is checked against
the event ID, dispatcher agent DID, source, and source sequence. The required
host verifier authenticates the receipt and validates its policy epoch against
the host's ingress-policy history; Workflows can only require a non-empty epoch
because Core 0.53.3 exposes no public policy-epoch provider to pin
independently. Workflows does not infer this proof from current registration
and does not inspect private Core tables. ACTION delivery remains ineligible
because it bypasses sanitization.

The host must also provide
`workflow_await_signal_privacy_transition_lock` through a public integration
surface. Core 0.53.3 keeps its corresponding agent lock private, so Workflows
does not reach into it; without the injected public lock the gate fails closed
before effect dispatch.

Core 0.53.3 serializes boundary capture, signal commit, and registration
backfill through one durable agent/source sequence domain on SQLite and
PostgreSQL. An event is eligible only when its `source_sequence` is strictly
greater than the persisted boundary sequence. `committed_at`, activation time,
delivery identity, and registration time are never *source-boundary*
eligibility fallbacks. Deadline eligibility is separate: a matching event wins
only when Core's linearized `committed_at` is strictly before the persisted
deadline; a commit exactly at the deadline belongs to timeout. Polling time
never changes that result. Timeout reconciliation gives publicly visible,
nonterminal pre-deadline deliveries a fixed 120-second grace after the
persisted deadline—two complete Core delivery-lease periods—to settle or
redrive. The grace is absolute and survives restart; reconciliation never
extends it. After it expires, timeout may win even when a source remains
disabled/unregistered, another executor still holds the lease, or Core's
public 1000-row inspection page is full. `deadline_won` evidence records every
visible unsettled pre-deadline delivery ID and whether that page hit the cap.
Malformed public rows without usable delivery IDs and failed initial drains
are represented by redacted synthetic unsettled identifiers; they receive the
same bounded grace and cannot bypass timeout liveness.
Core's public durable-consumer registration has no boundary field, so backfill
may materialize retained pre-boundary deliveries. Workflows validates every
public delivery against its persisted boundary, terminally NACKs a claimed
pre-boundary lease, and continues draining so a later post-boundary event is
not stranded. If Core claims the post-boundary row first, consumer cleanup may
terminalize the older row without creating Workflows evidence. A legacy row
without the complete boundary stays inspectable and cleanable after the
additive migration but fails closed for publication and resolution, including
on PostgreSQL.

Workflows uses a durable publication lease plus an `orphan_guard` tombstone
around the separate Core and Scheduler calls. Cancellation and force-abort
serialize with local publishers, remove exact returned resources after
ownership loss, and retain an unpurgeable retry intent after an interrupted
call whose eventual commit cannot be disproved. This is deliberately not
described as a cross-store atomic transaction.

Exact session selectors isolate runs by default; agent-wide broadcast is a
signed opt-in for INTERNAL events within the same user-agent tenant. Public,
external, and A2A-relayed events cannot win an agent-scoped wait; A2A authority
remains a separate surface. Recovery reads bounded owner/tenant/status-scoped
SQL pages through durable, wrapping cursors, quarantines malformed rows with
redacted structural audit evidence, and takes at most one public Scheduler
snapshot per pass.
Environmental registry reloads NACK for unbounded redelivery; immutable
scope mismatches ACK. Volatile, anonymized, and deidentified privacy transitions
are checked under Core's transition lock and atomically fence open waits. The
deadline winner takes the same lock and rechecks privacy before its row-locked
CAS. Timeout CAS eligibility and retention cleanup use database time; signal
arrival eligibility uses Core `committed_at`. Terminal recovery converges the
Core consumer and every related live Scheduler task while preserving fired
terminal one-shots as Scheduler audit history; purge waits for both cleanup
facts. A retention sweep supplied with the live dispatcher DID never performs
cleanup for an older/foreign dispatcher tenant: after retention expires it
persists a redacted stranded-resource receipt, visible through
`list_stranded_await_signal_retention`, and then purges the run. Omitting live
dispatcher context remains fail closed and lets outstanding cleanup pin the
run. Timeout wins compensate only the completed
await effect before the false branch proceeds; earlier PASS or irreversible
stages remain part of the live workflow. Shutdown drains boundedly and retains
unknown-effect evidence and leases for recovery when a handler resists
cancellation.

Delivery progress is currently periodic Workflows reconciliation, not a Core
event-driven callback. The feature reconciles once after initialization and
then every `min(lease_seconds / 3, 10 seconds)` (with a 50 ms floor), so the
default 30-second lease gives up to roughly 10 seconds of wake latency plus
processing time. Scheduler one-shots provide lower-latency timeout wakeups, but
each reconciliation/restore pass also scans a fair bounded database-clock lane
and resolves overdue waits through the same winner CAS, so timeout liveness
does not depend on Scheduler callback delivery. Availability requires the
Workflows recovery worker, its database, and Core durable delivery APIs;
Scheduler list/remove availability is still needed to converge live task
cleanup while preserving terminal Scheduler rows as audit history. A future
Core event-driven caller may reduce signal latency but is not part of this
release.

## Installation

```bash
uv pip install kestrel-feature-workflows
```

The package registers `WorkflowsFeature` through `kestrel_sovereign.features`
and `WorkflowsHostFeature` through `kestrel_sovereign.host_features`.

## Operator Runs API and console

Workflows 0.6.0 exposes its durable, engine-neutral run plane at
`/api/workflows/runs`. Authenticated operators can page and filter run records,
inspect stages, numbered attempts, typed external job correlations, and
artifact metadata, apply pause/resume/cancel/retry controls with idempotency and
sequence preconditions, and follow one authorized run through a polling-backed
SSE stream. Cross-tenant and absent identifiers share the same not-found
response, and artifact dereference returns metadata only.

`WorkflowsHostFeature` also contributes the capability-gated **Runs** panel to
the Console from package-owned JavaScript and CSS. The panel uses authenticated
streaming with polling fallback, renders generic SDK fields only, and offers an
optional correlation handoff to an installed Observability panel.

An injected `workflows.operator_context_resolver` remains authoritative for
Castle and other multi-tenant deployments. Otherwise Workflows resolves the
current host-scoped `claws.catalog>=1.3` service for each request and asks its
public operator-context resolver to authorize OAuth and other authenticated
solo operators. A present Claws service is authoritative: policy denial or an
invalid resolver fails closed and cannot fall through to broader local rights.
Generic Workflows hosts without a compatible Claws service retain the existing
zero-config fallback, which grants access only to the Sovereign API-key caller
and requires an injected tenant resolver. A present 1.2 catalog without the 1.3
operator policy is not considered absent and fails closed. The selected
resolver is responsible for user, tenant, boundary, capability, action, and
expiry policy.

The HTTP and Console surfaces intentionally do not launch runs. Launch remains
the feature-owned `RunService.launch_run` boundary used by installed execution
features, where source attribution, target boundaries, capabilities, tenancy,
and idempotency are authorized before acceptance. No Talon-, Eye-, Flight-,
repository-, command-, or filesystem-specific fields are part of this API.

## Development

```bash
uv sync --extra test
uv run --extra test pytest -q
npm test
```

## Design

See `docs/architecture/WORKFLOWS_FEATURE_DESIGN.md` (v4.1) and
`WORKFLOWS_DEVELOPER_GUIDE.md` in the kestrel-sovereign repository for the full
design and the stage-to-signal reduction.

## Retired hosted runtime shutdown (0.7.4)

After all native owners have physically joined, graceful executor-claim release
is optional lease acceleration. If the original database-bound host runtime is
already retired, shutdown does not admit new claim-release SQL; existing leases
remain for normal expiry/recovery. It does not revive host authority or report
claims released. Live and unbound hosts retain both executor/owner-scoped,
skip-locked releases. Foreign caller withdrawal, prior occurrence control,
known/unknown commits, native cleanup debt and any release already admitted
before a retirement race still propagate their actual terminal receipts.

## Resident recovery ownership (0.7.3)

The verified public Core 0.53.31 release is required. The first recovery scan remains under the caller's
startup admission; the long-lived recovery worker is then explicitly handed
off to Core's original runtime generation and READY barrier. Feature disable,
boot rollback and agent shutdown retain ownership of that same task. Ordinary
workflow effect children keep their caller admissions. Irreversible authority
or uncertain-commit failures terminalize recovery instead of becoming a logged
retry under revoked custody. Publication remains pending until the required
Core release is available and both release gates pass.

Temporary gate, winner-election and lease-heartbeat children are canceled and
physically joined by their original caller. Cancellation-resistant effect
tasks retain the existing bounded drain and durable unknown-effect evidence;
they are not reclassified as temporary helpers. Completed continuations and
retired runners retain their original control receipts through later shutdown,
and uncertain commits are never treated as serialization retries. Repeated
wait-provider registration is identity-owned and is removed at feature teardown.
PostgreSQL recovery claims skip run rows currently locked by an ACK, releasing
their checkout so terminal ACK persistence can progress within the existing pool.
Bulk retirement uses the same nonblocking row selection; locked claims retain
their original lease rather than blocking ACK persistence or consuming a fourth
database slot. Recovery scans advance by the selected native keyset, including
malformed or temporarily unverifiable rows. Each lane reaches its tail before
the next supervisor cycle retries preserved head rows.

Operator controls use an additive internal `control_revision` column. Pause,
resume and retry compare the original persisted revision, so a later pause wins
even across replicas and a PAUSED/RUNNING/PAUSED cycle. Retry resets and claims
the run in one transaction. Accepted consent/council resumes persist a recovery
intent: a replacement executor reevaluates the existing gate without dispatching
the stage effect again. Durable signal waits remain event-driven. Foreground
admissions retain original runtime custody through native commit and are joined
on retirement; wait-provider results never expose another owner's run payload.
Short native admissions are physically joined independently of the bounded
external-effect drain. Post-dispatch cursor updates compare both the observed
status and control revision, so an accepted pause or resume cannot be overwritten
by an older executor snapshot. Force-abort publication keeps the same original
retirement fence through terminal commit. Operator reconciliation preserves
native control receipts instead of treating them as uniqueness races. Recovery
keysets use the raw stored ordering value; malformed timestamp hydration cannot
prevent a lane from reaching valid rows behind it.

Foreground resume keeps the control revision observed when the request began,
not a newer snapshot obtained after claim or definition awaits. Its native
claim is owned by the same retiring admission fence. Pending-gate publication
preserves PAUSED, including an acknowledged pause during atomic await-signal
activation; that conflict cannot force the run to FAILED. Resumed consent and
council evaluations renew both original leases through their provider await.
Every per-run release uses nonblocking PostgreSQL row selection, just like
bulk retirement, so an ACK child retains its third checkout.

Shutdown physically joins native heartbeat, winner, journal and release tasks
independently of the external-effect deadline. A compensation that resists
cancellation after lease loss remains owned by its original task and durable
unknown-effect evidence until settlement. Native control receipts survive
lifecycle claim/renew/conflict normalization and the HTTP/SSE projection;
successful stream EOF must not stand in for an unknown or committed result.
Typed denial provenance distinguishes completed Scheduler occurrences from
the shared resident runtime. A denied original continuation keeps its receipt
and remains denied, while the existing live resident owner can recover eligible
durable work under its own original admission. Only exact occurrence-scoped
denials receive this treatment: unscoped authority errors, runtime loss,
uncertain/committed outcomes and failed physical closers still retire the runner.
Cancelled built-in CI polling carries its own typed poll lifetime rather than
an unscoped shared-runner denial. Retained completed local/occurrence denials are
bounded to the first 32 original receipts (including the first shutdown cause);
active callers retain their own exact errors. Stronger runtime/COMMIT/failed-close
receipts are not downgraded into this bounded local history.

A resumed await-signal activation reuses the original admitted stage, public
effect receipt and pre-effect wait boundary; it never redispatches the effect.
Pending gate results publish only against the revision that initiated their
evaluation. Late receipt writers admitted during draining are native owners and
are physically joined before shutdown returns. After the native-admission
cutoff, a still-unsettled external effect keeps its durable unknown marker and
cannot start a new storage writer past teardown. Force-abort journal failures
cannot mask a stronger receipt from the original compensation. Caller
cancellation is reported after native joins, unless stronger control evidence
takes precedence.

Durable successful-effect receipt writers are independent native owners, not
temporary lease helpers; stage cleanup cannot cancel them. Temporary-child
draining snapshots each arrival batch and physically joins native children
before selecting the original error. Explicit external resolver/gate children
instead share the same retirement handoff as stage/compensation effects; their
actual tasks remain strongly retained, without an extra timeout per child.
Foreground and background native drivers retain
their original invocation through inline compensation journals, transitions,
and claim release; shutdown joins invocation completion beyond the external-effect
budget, not the host caller's later work. Nested drives share that completion.
If an admission drain lets the invocation finish before cancellation reaches
its snapshot, the host caller is no longer an old-runner cancellation target.
Invocation-lifetime and abort-observer repairs alone did not close native
COMMIT retirement. Core now owns only the finite PostgreSQL exit/reset phases;
transaction bodies remain cancellable. A successful ACK and original reset can
attach a known-committed receipt to the exact original cancellation or local
denial without poisoning healthy shared runtime scopes. UNKNOWN, unscoped
control and actual failed closers remain fail-closed. This does not resolve
the complete external-wait contract by itself, nor claim full delivery approval.
Pre-COMMIT admission refusal
remains unchanged. Cancelling a force-abort observer is ordinary cancellation,
not proof that its abort event was set: it retains its original cancellation
through native cleanup and cannot fabricate an operator abort or FAILED run.
External effect stop requests do not re-cancel a task already unwinding a
delivered cancellation. Native-driver stop delivery is recorded per invocation:
historical cancellation counts on a reusable host cannot suppress the next
runner's first stop. All Workflow cancellation producers, including retirement,
share that owner-scoped delivery implementation. Separate effect/gate owners
retain their delivery record through `uncancel()` without retaining completed
tasks forever (weak keys). Admission waiters also forward caller cancellation
through the same owner via Core's synchronous cancellation-policy hook; they
still physically join native cleanup and retain the original caller receipt.
One delivered stop is not evidence of COMMIT/ACK settlement: the original native
completion and reset owners must actually settle. Shutdown preserves settled
local receipts separately from protocol failures, including its direct native
drain aggregations. Renewal intervals recheck Stop between the run and effect
writers, not merely before entering the interval.
Core delivery winners additionally retain the SAME confirmed lease lifetime
through native storage admission. An independent deadline owner expires that
scope even while the original public renewal call is stalled; a resistant
winner cannot regain admission after cancellation. Timely actual renewal
acknowledgements can advance the live interval, but no late acknowledgement can
revive an expired one. The monotonic lifetime implementation is shared with
Core's scheduler; this does not claim a cross-store atomic delivery/winner CAS.
Actual token loss likewise interrupts pre-CAS work while joining an already
accepted original COMMIT and retaining its known-committed result. Ordinary
scoped delivery expiry evidence is retained separately from shared shutdown
failure; UNKNOWN, foreign/unscoped control and physical retirement debts still
retire the shared runner. All newly created winner/renewal/deadline children
are reaped if subsequent coordinator creation is refused.
Only after those original children have joined, a wholly local delivery denial
with NO commit outcome or native debt becomes the ordinary retryable
`WorkflowLeaseLost` domain outcome. Its exact typed original is retained on
`original_delivery_control` and in the runner's bounded receipt inventory; this
does not reopen the denied scope. Caller cancellation and any committed,
unknown, foreign or unscoped control retain their original control path.
One task-local observation retains the exact independent caller cancellation
through the coordinator and temporary-child joins. If cancellation and local
expiry race, their original carriers are preserved explicitly and the outcome
cannot become a retryable domain loss. Historical task cancellation counts are
not used as evidence that this invocation was cancelled.
Trigger reconciliation and bounded delivery-page processing use that runner's
existing native admission owner too. A task-local original-runner pin refuses
replacement rather than borrowing a successor. The supervisor rechecks both
original runner and manager after reconciliation
joins, before admitting delivery processing; a replaced cycle ends while a
fresh cycle can use the successor normally. Retirement closes admission
before a resistant adapter can publish a new desired-state mutation, while an
already accepted original COMMIT/RESET is physically joined. During intentional
feature shutdown/replacement only, a settled local receipt or known pre-commit
denial of that same retired admission is retained without converting it into
shared host failure. Foreign/unscoped/UNKNOWN control and actual native debts
remain fail-closed; ordinary active lifecycle failures still propagate.
Admission joins separately retain the caller's original cancellation even
when a stronger committed child receipt is selected. Intentional replacement
cannot consume that observer cancellation as a clean local retirement.
Nested admissions on the same runner/task share that original invocation;
they do not create a second cancellation owner that could mistake the
runner's retirement request for an independent caller cancellation. Copied
contexts in different child tasks still acquire their own admissions.
Genuine signed aborts still publish their durable intent
and event; this does not assert that an unsettled effect has physically stopped.
Cancellation-resistant external effects are handed off to their own original
tasks with durable unknown-effect evidence. A retired native driver finishes
its cleanup instead of borrowing storage while waiting indefinitely for that
external effect, and late external settlement cannot start another journal.
Host effect-status resolvers (including compensation recovery) and gate
providers are invoked in separately owned tasks under the original runner
admission. Retirement hands off those actual external tasks while preserving
the unresolved durable attempt, not inventing resolver evidence or a gate FAIL.
A passive Core native observer separately joins accepted PostgreSQL transaction
exits and resets, even if a provider catches their control receipt and hangs
again. An open native body remains explicit retirement debt and fails closed;
it is never treated as a finite epilogue or a completed close. Stage and
compensation dispatches retain SignalDispatcher's separate original lifetime,
including its final public outcome journal; a Workflow observer must not revoke
that Core-owned journal's admission. Observer cancellation survives the native join; late ordinary writes
cannot borrow a successor admission. This change still requires its complete
scoped review/full gates and is not whole-branch release approval.
Renewal retirement explicitly retains its caller's original cancellation and
COMMIT classification alongside any heartbeat failure. Feature shutdown and
bounded drain observation use the existing cleanup caller rather than requiring
a new observer Task. If allocating a recovery-evidence writer fails, shutdown
still joins every already-accepted native owner, retains unresolved external
effects and leases, and reports the original refusal; it never calls the missing
evidence a successful journal write. The CI dependency lanes use `uv run --locked`;
the committed release lock must be refreshed against the actual published Core
floor before the downstream release can pass that gate.
The gate evaluator itself remains a native framework owner, but its body is
still cancellable on caller stop or lease loss; only individual injected host
callbacks enter external ownership. Built-in CI polling keeps
its actual HTTP worker in the native inventory independently of any wrapper,
and Core-owned red-team outcome journals do not inherit a host-provider fence.
Cancellation captured while reaping the retirement notification is included
before publishing evidence. Observer setup refusal retires and retains any
already registered provider instead of letting it run unobserved.
Host callbacks must do their work in that invocation's original context and
return a synchronous result or a fresh, unstarted coroutine. Pre-scheduled
Tasks/Futures and other opaque awaitables cannot acquire observation or runner
custody by being returned: they are refused, retained as explicit physical
debt, and fail the runner closed. A borrowed task is not cancelled as if the
runner had owned its native lifecycle. This applies to async callbacks that
return an awaitable as their result too.
The one implementation lives in `kestrel_sovereign.callbacks`; Workflow's
`host_callbacks` module re-exports that exact function and error class. Core's
wait-provider callbacks use the same return-value ownership contract.
The same callback boundary covers durable ingress/privacy verification and
HTTP operator, Claws-policy and tenant resolution. Ingress verification stays
inline in its original recovery driver, so a callback requesting shutdown does
not create a parent/child join cycle. Feature and Core drains exclude their
current physical Task while retaining that Task's original ownership until it
actually completes. Partial degraded-startup waiter admission closes refused
coroutines and joins every already-accepted waiter before reporting failure.

Local control classification requires exact scopes captured by the original
invocation or created by its own CI/delivery owner; a matching fence class is
not ownership. Delivery retry additionally requires the exact scope of that
specific winner invocation. Completion callbacks retain bounded original
receipt identities, not permission for a later invocation to localize a foreign
error. Actual PostgreSQL/Scheduler tests cover both foreign denial propagation
and independent admission after a known original-occurrence denial. These
proofs do not certify live Frinz post-READY or scale-to-zero acceptance.
The return-value check is shared by the runner and the production feature
adapters at the actual configured callback boundary. An adapter must not await
arbitrary host work first and thereby hide it inside a fresh coroutine. Script
compute and artifact-store calls use that same boundary.
Original effect-task retirement records outlive cleared live projections until
those tasks physically finish. Shutdown snapshots them before awaiting any
admission, so projection eviction cannot erase a required unknown-effect marker.
Force-abort re-harvests captured original receipts on every normal return too.
Cancellation barriers check terminal status within the locked transaction and
in the final UPDATE CAS: a completed/failed/cancelled run cannot be resurrected
as COMPENSATING by a stale cancellation reader.

Public restore/reconciliation callers are native drivers too: their actual
PostgreSQL acknowledgement and release remain physically owned through shutdown,
not just the background wrappers. SQLite admission starts its immediate
transaction before sampling the lease clock, so queued writers cannot spend
an expired observation after lock acquisition. Resumed signal waits retain the
original successful effect output before activation and never redispatch it.
Operator-run producers use the public backend transaction contract with a
first-statement SQLite write lock before sampling the database lease clock.
Lease renewal, stage/attempt/output publication and terminal transitions cannot
reuse a timestamp from before a native writer-lock wait; publication rechecks
eligibility after child writes too. SQLite lease clocks retain milliseconds.

`compensation_success_status` is a nullable, additive durable run field. It
retains the original failed/cancelled disposition across ambiguous compensation
and restart; a recovered ordinary failure must not silently become cancellation.
The first durable cancellation barrier and COMPENSATING transition retain that
disposition atomically. Irreversible residue preserves FAILED for failed runs;
cancelled runs retain CANCELLED_WITH_IRREVERSIBLE_RESIDUE after recovery.
Force-abort reconciliation is limited to the run's admitted await-signal effects
and cannot execute unrelated ordinary effects. Explicit required projections are
already refused by the signed await-signal model; recovery remains fail-closed
on malformed or unsupported persisted projection definitions.

Stage links also retain nullable, additive `compensation_effect_status` and
`compensation_effect_completed_at` fields. A late native undo result is recorded
against its original durable `compensation_signal_id`, independently of lease
loss or caller cancellation. Recovery can consume that receipt without a host
resolver and cannot substitute a forward-effect receipt, an unrelated signal,
or a conflicting terminal result. Built-in GitHub CI polling joins the original
native HTTP worker on retirement and checks its captured authority before every
subsequent request, including urllib's automatic redirects. Authenticated
redirects must retain the original origin (scheme, host and port). Redirect and
HTTP-error responses are physically closed in that original worker even after
admission retires; an actual failed close retains the original resource and
closer as control evidence rather than silently relying on garbage collection.
### Native continuation and renewal custody

Hosted durable continuations use Core's original resident task publisher after
run acceptance. Their original runtime/feature admission stays enforced without
borrowing a completed cron or tool-call scope. Ordinary child tasks keep all
caller scopes; scoped standalone integrations must explicitly configure
`continuation_task_factory` before background acceptance. The completion and
parked-resume callback uses the same actual resident context.

Native heartbeat intervals stop cooperatively on normal completion. Their
already-entered database acknowledgements are physically joined, never cancelled
to finish a successful gate/effect. Genuine delivery-lease loss still interrupts
pre-CAS winner work and preserves any actual irreversible receipt. Shutdown
joins native owners and reports retained occurrence controls on busy exits;
idle claim cleanup precedes reporting those occurrence-only receipts.
Caller cancellation joins the original winner/lease coordinator without
stopping Core renewal early. Genuine Core lease loss still interrupts pre-CAS
work and preserves an already-entered native COMMIT outcome. Force-abort event
waiters are cancellable bookkeeping, not native database acknowledgement owners.

Finite lifecycle boundaries use Core's canonical source-isolating composition:
the caller receives its actual cancellation alongside the exact native receipt,
while shared shutdown latches retain native sources only. Local delivery-loss
translation never consumes an independent caller withdrawal, native abort,
failed closer, or irreversible outcome. Renewal confirmation uses monotonic time
captured before the request plus Core's server expiry-minus-update interval;
late acknowledgements and backward host wall clocks cannot extend admission.

Original local-scope provenance follows exact native source objects across
canonical regrouping and independent shutdown readers. Source keys and scope
references are weak and identity-checked; fresh observation envelopes do not
consume a permanent history slot. This is classification evidence only, never
permission for a later reader to execute under an old scope. Native aborts are
checked through Core's explicit cause/group graph before local retirement.
